Sketch on face
In the previous chapter, we looked at how KCL lets you tag edges. Tags let you query your edges (to find their length, or angle with the previous edge), or apply an edge cut (like a fillet or chamfer). But you can tag more than just edges! In this chapter, we'll learn how to tag faces, and how that lets you build more complicated 3D models.
Side faces
Let's start with a simple example. First, we'll sketch and extrude a triangle. We'll tag its second edge as b
.
length = 20
triangle = startSketchOn(XY)
|> startProfile(at = [-length, -length])
|> line(end = [length, 0])
|> line(end = [length, length * 2], tag = $b)
|> line(endAbsolute = profileStart())
|> close()
|> extrude(length = 40)
b
also has the tag b
. We can use this to reference this face in our 3D model.
Now, if we want to start a new sketch on that face, we can do so!
sketch001 = startSketchOn(triangle, face = b)
Note that we previously passed a plane (like XY or YZ) into startSketchOn
. But now, we're passing a solid (our extruded triangle) instead. The solid has five faces (three side faces, a bottom, and a top), so we tell startSketchOn
which face in particular we want to sketch on. The face is tagged b
(because it was created from an edge which was tagged b
), so we just pass that in too. Now we can start sketching on this face, and even extrude that sketch too.
length = 20
triangle = startSketchOn(XY)
|> startProfile(at = [-length, -length])
|> line(end = [length, 0])
|> line(end = [length, length * 2], tag = $b)
|> line(endAbsolute = profileStart())
|> close()
|> extrude(length = 40)
cylinder = startSketchOn(triangle, face = b)
|> circle(radius = 10, center = [0, 15])
|> extrude(length = 40)
Note: When you sketch on a face, the sketch uses the global coordinate system. This means when you use 2D points in your sketches, they're relative to the overall global scene, and not the face you're sketching on.
Sketching on faces is a really common pattern when designing real-world objects. A LEGO brick is a good example -- first you'd sketch the rectangular brick, then you'd sketch on its top face, adding the little bumps on top. But wait a second. How would we tell startSketchOn
to sketch on the top face of the brick? That face isn't created from any particular edge. So we can't tag its line
call and then reuse that tag for the face. What should we do?
Standard faces
There's a simple solution to sketching on the top face. KCL has some built-in identifiers for the top and bottom face, START
and END
. We prefer the terms "start" and "end" to "top" and "bottom" because the latter depend on your camera angle, so they can be ambiguous. "Start" always refers to the original face from your 2D sketch. "End" always refers to the new face created at the end of the extrusion. Let's use them!
length = 20
triangle = startSketchOn(XY)
|> startProfile(at = [-length, -length])
|> line(end = [length, 0])
|> line(end = [length, length * 2])
|> line(endAbsolute = profileStart())
|> close()
|> extrude(length = 40)
cylinder = startSketchOn(triangle, face = END)
|> circle(radius = 3, center = [0, -10])
|> extrude(length = 40)
box = startSketchOn(triangle, face = START)
|> polygon(radius = 8, numSides = 4, center = [0, -15])
|> extrude(length = 10)
Sketch on chamfer
When you chamfer
an edge, it creates a new face, which can also be sketched on! Consider this chamfered cube from the previous chapter:
length = 20
cube = startSketchOn(XY)
|> startProfile(at = [-length, -length])
|> line(end = [length, 0], tag = $a)
|> line(end = [0, length], tag = $b)
|> line(end = [-length, 0], tag = $c)
|> line(end = [0, -length], tag = $d)
|> close()
|> extrude(length = length)
|> chamfer(
length = 2,
tags = [
getOppositeEdge(a),
],
)
chamfer
call, and then we can sketch on it like any other tagged face.
length = 20
cube = startSketchOn(XY)
|> startProfile(at = [-length, -length])
|> line(end = [length, 0], tag = $a)
|> line(end = [0, length], tag = $b)
|> line(end = [-length, 0], tag = $c)
|> line(end = [0, -length], tag = $d)
|> close()
|> extrude(length = length)
|> chamfer(
length = 2,
tags = [
getOppositeEdge(a),
],
tag = $chamferedFace
)
startSketchOn(cube, face = chamferedFace)
|> circle(radius = 1, center = [-length/2, 0])
|> extrude(length = 40)
Defining new planes
When you call startSketchOn(XY)
, you're passing a plane as the first argument. XY is a standard, built-in plane (remember, there are six -- XY, YZ, XZ, -XY, -YZ and -XZ). But you can easily define your own planes too! There's two ways:
Offset planes
You can use the offsetPlane
function to copy any other plane, but moved some direction up or down the third axis. For example, let's draw a small circle on XY, a medium circle on a plane 10 units above it, and a big circle 20 units above it.
r = 10
startSketchOn(XY)
|> circle(center = [0, 0], radius = r)
|> extrude(length = 1)
startSketchOn(offsetPlane(XY, offset = 10))
|> circle(center = [0, 0], radius = 2 * r)
|> extrude(length = 1)
startSketchOn(offsetPlane(XY, offset = 20))
|> circle(center = [0, 0], radius = 3 * r)
|> extrude(length = 1)
Custom planes
You can define your own plane with your own axes like this:
customPlane = {
origin = { x = 0, y = 1, z = 0},
xAxis = { x = 1, y = 0, z = 0 },
yAxis = { x = 0, y = 0, z = 1 },
}
Note the custom plane has a few properties:
- An origin, which is a 3D point in space, using the global coordinate system (i.e. it's relative to the overall scene)
- X and Y axes, which are defined as vectors
The plane's Z axis is the cross product of its X and Y axes. It's uniquely determined, so you don't need to specify it.
Now let's use this custom plane in a sketch. We'll build two identical cylinders, but one is on the standard XY plane, and one is on the custom plane we defined above.
r = 10
startSketchOn(XY)
|> circle(center = [100, 0], radius = r)
|> extrude(length = 10)
customPlane = {
origin = {
x = 0,
y = 0,
z = 0
},
xAxis = { x = 1, y = 0.5, z = 0 },
yAxis = { x = 0, y = 0.5, z = 1 }
}
startSketchOn(customPlane)
|> circle(center = [0, 0], radius = r)
|> extrude(length = 10)
offsetPlane
if you've already defined a plane on the same X and Y axis. You can even use offsetPlane
to offset a custom plane, like this:
// Make a custom plane.
customPlane = {
origin = { x = 0, y = 1, z = 0},
xAxis = { x = 1, y = 0, z = 0 },
yAxis = { x = 0, y = 0, z = 1 },
}
// Now offset it 20 up its normal axis.
newPlane = offsetPlane(customPlane, offset = 20)
Now we've learned how to sketch on all sorts of things:
- Standard planes like XY or -XZ
- Tagged faces of existing solids
- Top or bottom faces of solids, using
START
andEND
- Chamfered faces cut out of solids, by tagging the
chamfer
call - Custom planes (truly custom, or just offset from an existing plane)
This gives you a lot of flexibility in building your solids. Now it's time to learn what else we can do with these solids. The next chapter will teach you how to combine and transform them!