Yet Another Newbi struggles with 'radiusArc'

429 views
Skip to first unread message

mayor84

unread,
Aug 28, 2021, 8:24:38 PM8/28/21
to CadQuery
'''
Hello, Everybody!
I am newbi in cadquery and python. And I'm trying to make the following code
work on full range of values(-360..360) for angle1 and angle2. It seems to me
that I'm missing something trivial here. Am I making a math mistake? Maybe 'radiusArc'
doesn't work correctly? Or 'radiusArc' works just fine and perhaps I have to write some kind of 
'polarRadiusArc' function where I stitch together 2 radiusArcs to be able make
full circle out of 2 angles and radius. And here I'm getting lost again. Why 'pie2'
works only with range -20..20. Is there special cases when I need to stitch together 
more than 2 radiusArcs?
Thanks
'''

import cadquery as cq
from math import *

def p2c(radius, angle):
    theta = radians(angle)
    return (radius * cos(theta), radius * sin(theta))

def pie1 (self, radius1, radius2, angle1, angle2):
    p1 = p2c(radius1, angle1)
    p2 = p2c(radius2, angle1)
    p3 = p2c(radius2, angle2)
    p4 = p2c(radius1, angle2)
    return (self.moveTo(*p1).lineTo(*p2).radiusArc(p3, -radius2)
            .lineTo(*p4).radiusArc(p1, radius1).close())

cq.Workplane.pie1 = pie1

def pie2(self, radius1, radius2, angle1, angle2):
    radius3 = abs(radius1 - radius2) / 2
    p1 = p2c(radius1, angle1)
    p2 = p2c(radius2, angle1)
    p3 = p2c(radius2, angle2)
    p4 = p2c(radius1, angle2)
    return (self.moveTo(*p1)
        .radiusArc(p2, -radius3)
        .radiusArc(p3, -radius2)
        .radiusArc(p4, -radius3)
        .radiusArc(p1, radius1).close())

cq.Workplane.pie2 = pie2

result = (
    # for angle1 and angle2 in the range of -90 to 90 it seems to work just fine
    #cq.Workplane("front").pie1(80, 120, 90, -90)
    
    # it distorts when the difference between the angles is more than 180 degrees
    #cq.Workplane("front").pie1(80, 120, -135, 90)
    
    # Or throws the error: Arc radius is not large enough to reach the end point
    #cq.Workplane("front").pie1(80, 120, -135, 45)
    
    # Just fine again
    #cq.Workplane("front").pie1(80, 120, -135, 44.999)
    
    # And its getting worse for pie2, the working range reduces to only -20 to 20
    #cq.Workplane("front").pie2(80, 120, -30, 9)
    
    # And all the sudden works again on -90, 90
    #cq.Workplane("front").pie2(80, 120, -90, 90)
    
    # Works too
    cq.Workplane("front").pie2(80, 120, -120, 59.99)
).extrude(10)

Lorenz

unread,
Aug 29, 2021, 8:37:41 AM8/29/21
to CadQuery
Hi, Learning Python with CadQuery should be fun as you can visualize your results.

># it distorts when the difference between the angles is more than 180 degrees
>#cq.Workplane("front").pie1(80, 120, -135, 90)

I checked this case. Here is the 2D drawing with labeled points:
arc1.png


The problem is pie1() draws the radiusArc in this case with counter-clockwise arc in 2,3 and clockwise arc in 4,1.

r = cq.Workplane("front").moveTo(*p1).lineTo(*p2).radiusArc(p3, -radius2).lineTo(*p4).radiusArc(p1, radius1)

To get the expected result for this case:

r = cq.Workplane("front").moveTo(*p1).lineTo(*p2).radiusArc(p3, radius2).lineTo(*p4).radiusArc(p1, -radius1)

This is 2,3: clockwise and 4,1: counter-clockwise.  

arc2.png


Lorenz

mayor84

unread,
Aug 29, 2021, 1:15:23 PM8/29/21
to CadQuery
>> Hi, Learning Python with CadQuery should be fun as you can visualize your results.

Hi, Lorenz! Thank you for your fast answer. And that is very true about learning, it's much easier to understand when you actually see what it's doing.

>> I checked this case. Here is the 2D drawing with labeled points:

You're making a good point here. Basically by changing direction of drawing those lines, you made those arcs less than 180 degree "long". So "distortion" disappeared. The question is, Is it normal behavior for 'radiusArc'. Why I cannot make this arc 355 degree "long", without getting it distorted? I didn't see any mention of that in documentation.

And also, looks like I failed to clearly explain what I'm trying to achieve. In the first place I was trying to make the shape to look like this:

cq.Workplane("front").pie2(80, 120, -120, 59.99).pie2(80, 120, 0, 120).combine()

radiusArc11.png

And also make it more or less universal and actually parametric. So I can set my angles and radii and get the shape. And also learn best practices and cadquery standarts in the process. It is very possible that I took a wrong approach. Maybe instead of using math functions I should've used cadquery functions like 'rotate()' and 'translate()'. It possibly could make the code more readable and understandable. But that example didn't work when I was tinkering with it.

Lorenz

unread,
Aug 29, 2021, 4:57:20 PM8/29/21
to CadQuery
I see that radiusArc calls sagittaArc with sag value computed as:

    sag = abs(radius) - math.sqrt(radius ** 2 - length ** 2)

So I think radiusArc can generate only the blue or yellow arcs here:
Screenshot from 2021-08-29 16-02-00.png


For the desired arc, perhaps try a different method.  I used threePointArc (red):

    p1b = (radius1, 0)
    tpa = cq.Workplane("front").moveTo(*p4).threePointArc(p1b, p1)

Roger Maitland

unread,
Aug 29, 2021, 9:06:19 PM8/29/21
to CadQuery
The offset2D() method might be helpful here.

Cheers,
Roger

mayor84

unread,
Aug 29, 2021, 10:24:58 PM8/29/21
to CadQuery
Thank you for making me finally read the code of cadquery. :D Now I've got a lot to dig through here. :)
'threePointArc' is much closer to bare metal, internally calls GC_MakeArcOfCircle. 
'sagittaArc' and 'radiusArc' add more complexity to it which I didn't need for my purpose.
I guess it is one of those cases of https://en.wikipedia.org/wiki/Leaky_abstraction.

I didn't finish my code yet, which using 'threePointArc'. But my first experiments are telling me that it's definetly the way to go.
Tomorrow, after work I'll share my results.

Also, Lorenz, could you share with me how do you make those labels and "construction" lines? 

Also, I have a kind of side question. Is it possible to "connect" cadquery sources to CQ-Editor so I can step through its code with a debugger? Link for a tutorial would be best!

Jeremy Wright

unread,
Aug 30, 2021, 6:58:52 AM8/30/21
to CadQuery
There is some basic info on debugging in the readme: https://github.com/CadQuery/CQ-editor#debugging-objects

Roger Maitland

unread,
Aug 30, 2021, 11:42:52 AM8/30/21
to mayor84, CadQuery
Cadquery is easy to extend such that you can work with your own custom shapes. For example, your project might benefit from a 2D sector shape (i.e. a slice of pie) which fts into the cadquery pipeline like this:
import math
import cadquery as cq


def arc_pnts(radius: float, angle: float) -> cq.Vector:
return cq.Vector(
radius * math.cos(math.radians(angle)),
radius * math.sin(math.radians(angle)),
0,
)


def _sector2D(self, radius: float, arc_size: float) -> cq.Workplane:
""" The shape enclosed between an arc and the two radii at either end of that arc
where arc_size is measured in degrees """
arc_points = [arc_pnts(radius, arc_size * frac) for frac in [0, 0.5, 1]]
sector = (
cq.Workplane("XY")
.hLineTo(arc_points[0].x)
.threePointArc(arc_points[1], arc_points[2])
.close()
)
return self.eachpoint(lambda loc: sector.val().moved(loc), True)


cq.Workplane.sector2D = _sector2D

pie = (
cq.Workplane("XY")
.sector2D(10, 50)
.extrude(10)
.faces(">Z")
.workplane()
.hole(diameter=18)
)


Once sector2D() builds the sector shape other standard methods can be applied like extrude() or hole() or fillet() or chamfer()... The eachpoint() method in the _sector2D() method enables the use of sector2D at multiple locations, for example those created by the rarray() or polarArray() methods.

Cadquery is endless fun 😀

Cheers,
Roger

--
cadquery home: https://github.com/CadQuery/cadquery
post issues at https://github.com/CadQuery/cadquery/issues
run it at home at : https://github.com/CadQuery/CQ-editor
---
You received this message because you are subscribed to a topic in the Google Groups "CadQuery" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/cadquery/DbFGAxJw9vg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to cadquery+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cadquery/b7e13a0c-2b92-432b-b980-9eda6fef01e0n%40googlegroups.com.

Lorenz Neureuter

unread,
Aug 30, 2021, 8:04:51 PM8/30/21
to Roger Maitland, mayor84, CadQuery
>how do you make those labels and "construction" lines?

There is a text() method that you can use to say cut text into your part.

Example extruding text at a point for annotation:

cq.Workplane("XY").center(20,50).text("A",10,0.5)


Use show_object() with CQ-Editor to display with color and transparency:

show_object(myobj, name="myobj", options = {"color":"red", "alpha":0.5})

mayor84

unread,
Aug 30, 2021, 11:33:10 PM8/30/21
to CadQuery
So. Here is my promised code. It's finally doing exactly what I wanted it to do!
import cadquery as cq
from math import (radians, sin, cos, pow, sqrt, hypot)

def p2c(radius, angle):
    theta = radians(angle)
    return (radius * cos(theta), radius * sin(theta))

def cake(self, r1, r2, a1, a2):
    # tangentArcPoint is better solution than my attempts to crunch numbers by "hand"
    #r3 = abs(r1 - r2 - 2.) / 2 + 1
    a3 = abs(a1 - a2 - 2.) / 2 + 1
    
    p1 = p2c(r1, a1)
    mp1 = p2c(r1, a3)
    p2 = p2c(r1, a2)
            
    p3 = p2c(r2, a2)
    mp2 = p2c(r2, a3)
    p4 = p2c(r2, a1)
    
    return (self.moveTo(*p1)
            .threePointArc(mp1, p2)
            .tangentArcPoint(p3, relative=False)
            .threePointArc(mp2, p4)
            .tangentArcPoint(p1, relative=False).close())

cq.Workplane.cake = cake

#cq.Workplane("XY").cake(80, 120, -20, 20)
#cq.Workplane("XY").cake(80, 120, -120, 120)


result = (
[cq.Workplane("XY").center(500,0).cake(80, 120, -20, 20),
 cq.Workplane("XY").center(-500,0).cake(80, 120, -120, 120),
 cq.Workplane("XY").cake(80, 120, -45, 45),
 cq.Workplane("XY").center(20,50).text("A",10,0.5)]
)


show_object(result)

radiusArc22.png

>> There is some basic info on debugging in the readme: https://github.com/CadQuery/CQ-editor#debugging-objects
Thanks, Jeremy Wright. I'll check it out.

>> Example extruding text at a point for annotation:
Yes. I finally get it! Thanks, Lorenz. I had a problem with disappearing of an object I created before. So the solution to call 'show_object' for each of them. 
Or put them all in an array and call 'show_object' with it.

Also, I really like how's Roger's code written. I guess my next step is to make something similar with mine.

Also, I guess I have to explain. Couple years ago I was already trying to get into 3d design. Since then only fragmented memories left. I think, I was doing some kind of exersice or tutorial. I think I was doing it in OpenSCAD. Because FreeCAD was always crushing on me and very often just dead hanging my laptop. And that shape I was trying to create and kept failing to explain here, was just sitting in my brain as a picture and some math behind it. And only today I also recovered from my memory that those 4 points are joints between 4 arcs, and each pair of arcs in those points supposed to be tangent to each other. It makes those joints "smooth", "seamless". And also if I remember correctly, OpenSCAD doesn't make a real continuous geometry. It chops everything on segments. And it was frustrating me at some point. I don't even remember why. 

Anyway. I'm so glad I found such a powerful tool as cadquery and this very helpful community. For right now I decided, every weekend or so to do some cad exercises I found on the internet. Using cadquery of course. And public it on GitHub so I wouldn't have those fragmented memories anymore. Once I manage to do it, I'll drop a link to it here as well. Thanks a lot, Guys! :)

mayor84

unread,
Aug 31, 2021, 12:39:35 AM8/31/21
to CadQuery
Upd: I found that shape! And it's defined in terms of angles and radii! At least something I remembered right. :)Exer3.png

ilteris...@gmail.com

unread,
Oct 5, 2022, 10:07:12 AM10/5/22
to CadQuery
Hello, appreciate your hard work. These type of rounded slots can also be done by offset2D() method, as suggested above. 
I add an example for future reference. 

import cadquery as cq

rounded_slot = (
    cq.Workplane()
   
    # The reference arc that we are going to use to offset
    .moveTo(-135, 0)
    .polarLine(135, 37, forConstruction=True)
    .radiusArc((0, 0), 135)
    .mirrorX()
   
    # offset slots
    .offset2D(10)
)

show_object(rounded_slot)

rounded_slot.png

Below is a quick-and-dirty solution for your drawing (I added a small thickness and convert it into 3D)
The design is not parametric, I just embed the dimensions provided.

import cadquery as cq

part = (
    cq.Workplane()
    .moveTo(50+43.4+10-135)
    .polarLine(135, 37, forConstruction=True)
    .radiusArc((50+43.4+10, 0), 135)
    .mirrorX()
    .offset2D(20)
    .extrude(2)
    .faces(">Z").workplane()
    .moveTo(50+43.4+10-135)
    .polarLine(135, 37, forConstruction=True)
    .radiusArc((50+43.4+10, 0), 135)
    .mirrorX()
    .offset2D(10)
    .cutThruAll()
    .faces("<Z").workplane()
    .circle(50).extrude(-2)
    .faces("<Z").workplane()
    .rect(50+38, 40, centered=(False, True)).extrude(-2)
    .faces("<Z").workplane()
    .circle(15)
    .polarArray(32.5, 30, 360, 6)
    .circle(11)
    .cutThruAll()
    .faces("+Y or -Y").edges("|Z")
    .fillet(5)
)
show_object(part)

rounded_slot_drawing.png

31 Ağustos 2021 Salı tarihinde saat 07:39:35 UTC+3 itibarıyla may...@gmail.com şunları yazdı:
Reply all
Reply to author
Forward
0 new messages