A couple of beginner questions (holes on a line segment, fillet-like things)

41 views
Skip to first unread message

george hartzell

unread,
Mar 28, 2024, 8:01:38 PMMar 28
to CadQuery
Hi All,
I'm just getting started with CadQuery, my first project is a box for a Sonnof SV board and some connectors.

I've been experimenting with the parametric enclosure example and have something that generally works, but I feel like I've been beating on a couple of things with a big hammer to make them fit (figuratively).

Here's a bit of sample code that illustrates a couple of questions.  It should generate a cube with a couple of rounded feet/tabs sticking out with screw holes.  I'd like something like a fillet, but in the shape that results when you swipe a rounded object (finger tip) along a bead of caulk.

I'd love any comments about better ways to build this, in particular how to locate/create the two screw holes and how to generate the rounded fillet.

Thanks in advance,

g.

```
import cadquery as cq

box = cq.Workplane("XY").rect(50, 100).extrude(20)

# Is there a prettier way to locate the holes than drawing a rect of
# x=0 and then calling vertices.  Seems wasteful to create 4 holes, in
# overlapping pairs...
feet = cq.Workplane("XY").rect(10, 120).extrude(3).edges("Z").fillet(4)
holes = (
    cq.Workplane("XY")
    .rect(0, 112, forConstruction=True)
    .vertices()
    .circle(1.5)
    .extrude(3)
)
feet = feet.cut(holes)

# Two things I don't like here:
#  - I'd like an operation like "fillet" that does this cube minus the
#    circle.
#  - It seems like I should be able to center the tube along the edges
#    where the foot and box intersect, rather than just "mathing" it
#    out there...
fillet = cq.Workplane("XY").rect(10, 107).extrude(6)
tube = cq.Workplane("YZ").circle(3).extrude(10)
fillet = fillet.cut(tube.translate((-5, -53, 6)))
fillet = fillet.cut(tube.translate((-5, 53, 6)))

item = box.union(feet).union(fillet)
show_object(item)
```

george hartzell

unread,
Mar 28, 2024, 8:13:55 PMMar 28
to CadQuery
Well, a bit more reading and answered my question about using the rect to draw two circles; just use a line....

E.g.,

```
my_line = cq.Workplane("XY").vLine(20)
debug(my_line.vertices().circle(3).extrude(5))
```

still curious about the fillet-like thing and general feedback.

Thanks,

g.

Lorenz

unread,
Mar 30, 2024, 10:52:37 AMMar 30
to CadQuery

Here is an example using BoxSelector to help select the edges for fillet.

>general feedback
For multiple feet consider Workplane each (or maybe mirror) or Sketch each.  Here is an example using Sketch.


```py
import cadquery as cq

w, l, h = 50, 100, 20
hfoot = 4

box = cq.Workplane("XY").rect(w, l).extrude(h)

# feet
sk0 = (
    cq.Sketch()
    .push([(5, 0)])
    .rect(10, 10, tag="rect")
    .reset()
    .vertices(">X")
    .fillet(2)  # issue with fillet after hole, move before hole
    .segment((0, 0), (6, 0), tag="hole", forConstruction=True)
    .vertices(">X", tag="hole")
    .circle(1.5, mode="s")
    .clean()
)

# manually locate feet
# sketches_feet = [
#     sk0.moved(cq.Location((w / 2, l / 2 - 20, 0), (0, 0, 1), 0)),
#     sk0.moved(cq.Location((w / 2, -l / 2 + 20, 0), (0, 0, 1), 0)),
#     sk0.moved(cq.Location((-w / 2, l / 2 - 20, 0), (0, 0, 1), 180)),
#     sk0.moved(cq.Location((-w / 2, -l / 2 + 20, 0), (0, 0, 1), 180)),
#     sk0.moved(cq.Location((0, l / 2, 0), (0, 0, 1), 90)),
#     sk0.moved(cq.Location((0, -l / 2, 0), (0, 0, 1), 270)),
# ]

# or selecting box edges for foot placement
sketches_feet = [
    # two feet on long edges, one on short edges
    (
        cq.Sketch()
        .edge(box.edges("<Z and >X").val())
        .edges()
        .distribute(2, 0.2, 0.8, rotate=False)
        .each(lambda loc: sk0.moved(loc))
    ),
    (
        cq.Sketch()
        .edge(box.edges("<Z and <X").val())
        .edges()
        .distribute(2, 0.2, 0.8, rotate=False)
        .each(lambda loc: sk0.moved(loc * cq.Location((0, 0, 0), (0, 0, 1), 180)))
    ),
    (
        cq.Sketch()
        .edge(box.edges("<Z and >Y").val())
        .edges()
        .each(lambda loc: sk0.moved(loc * cq.Location((0, 0, 0), (0, 0, 1), 90)))
    ),
    (
        cq.Sketch()
        .edge(box.edges("<Z and <Y").val())
        .edges()
        .each(lambda loc: sk0.moved(loc * cq.Location((0, 0, 0), (0, 0, 1), 270)))
    ),
]

feet = cq.Workplane().placeSketch(*sketches_feet).extrude(hfoot)
res = box.union(feet)

# fillet box-foot
eps = 1e-3
res = (
    res.edges(
        cq.selectors.BoxSelector(
            (-(w + eps) / 2, -(l + eps) / 2, hfoot - eps),
            ((w + eps) / 2, (l + eps) / 2, hfoot + eps),
        )
    )
    .edges("|X or |Y")
    .fillet(3)
)

```

george hartzell

unread,
Mar 31, 2024, 6:45:45 PMMar 31
to CadQuery
@lorenz, thank you!

A bunch of nice patterns in there to think about!

It seems like `fillet` behaves differently based on whether the edge is "inside" or "outside".  All of the examples in the docs use it to round e.g. the outside edge of a cube, but in this case the edge is "in a corner" and results in the finger-wiped-caulk effect that I'm looking for.  That's not mentioned in the docs, as far as I can tell.  MIght be a good PR for me, though I'm not sure what the rights terms are for "inside" and "outside"....

After drawing debugging versions of various objects, I think that there is an extraneous edges filter in your example, the two debug statements below seem to return the same set of edges.  At first I thought that it might be filtering out the "vertical" edge where the foot meets the box, but the center of that object isn't in the skinny box within which you're selecting.

``` py
# fillet box-foot
eps = 1e-3
s = cq.selectors.BoxSelector(

    (-(w + eps) / 2, -(l + eps) / 2, hfoot - eps),
    ((w + eps) / 2, (l + eps) / 2, hfoot + eps),
)

debug(res.edges(s))
debug(res.edges(s).edges("|X or |Y"))
```

I'm curious (more poking to do) where there's a way to explicitly grab the edges that result from the fusion of the box and the feet (or, that are used inside the sketch to *define* the feet).

Thank you again for giving me things to chew on....

g.

Lorenz

unread,
Mar 31, 2024, 10:34:01 PMMar 31
to CadQuery
> there is an extraneous edges filter in your example
You are right!  I started with the parallel dir selector then added the box selector later.  The parallel dir selector can be omitted.



> I'm not sure what the rights terms are for "inside" and "outside"....
Here is a description in the OCCT user guide (Fillets and Chamfers):  
https://dev.opencascade.org/doc/overview/html/occt_user_guides__modeling_algos.html
"A fillet description contains an edge and a radius. The edge must be shared by two faces. The fillet is automatically extended to all edges in a smooth continuity with the original edge. "



>(or, that are used inside the sketch to *define* the feet).
Modifying previous example:
```py
feet = cq.Workplane().placeSketch(*sketches_feet).extrude(hfoot)
feet.faces(">Z").edges(cq.selectors.LengthNthSelector(-1)).tag("foot_to_fillet")

res = box.union(feet)
res = res.edges(tag="foot_to_fillet").fillet(3)
```
Reply all
Reply to author
Forward
0 new messages