11#! /usr/bin/env python3
2+ from solid .solidpython import OpenSCADObject
23import sys
3- from math import cos , radians , sin
4+ from math import cos , radians , sin , pi , tau
5+ from pathlib import Path
46
5- from euclid3 import Point3
7+ from euclid3 import Point2 , Point3
68
7- from solid import scad_render_to_file
8- from solid .utils import extrude_along_path
9+ from solid import scad_render_to_file , text , translate
10+ from solid .utils import extrude_along_path , right
11+
12+
13+ from typing import Set , Sequence , List , Callable , Optional , Union , Iterable
914
1015SEGMENTS = 48
1116
1217
1318def sinusoidal_ring (rad = 25 , segments = SEGMENTS ):
1419 outline = []
1520 for i in range (segments ):
16- angle = i * 360 / segments
17- x = rad * cos (radians (angle ))
18- y = rad * sin (radians (angle ))
19- z = 2 * sin (radians (angle * 6 ))
21+ angle = radians (i * 360 / segments )
22+ scaled_rad = (1 + 0.18 * cos (angle * 5 )) * rad
23+ x = scaled_rad * cos (angle )
24+ y = scaled_rad * sin (angle )
25+ z = 0
26+ # Or stir it up and add an oscillation in z as well
27+ # z = 3 * sin(angle * 6)
2028 outline .append (Point3 (x , y , z ))
2129 return outline
2230
@@ -29,28 +37,68 @@ def star(num_points=5, outer_rad=15, dip_factor=0.5):
2937 star_pts .append (Point3 (rad * cos (angle ), rad * sin (angle ), 0 ))
3038 return star_pts
3139
40+ def circle_points (rad : float = 15 , num_points : int = SEGMENTS ) -> List [Point2 ]:
41+ angles = [tau / num_points * i for i in range (num_points )]
42+ points = list ([Point2 (rad * cos (a ), rad * sin (a )) for a in angles ])
43+ return points
3244
3345def extrude_example ():
3446 # Note the incorrect triangulation at the two ends of the path. This
3547 # is because star isn't convex, and the triangulation algorithm for
3648 # the two end caps only works for convex shapes.
49+ path_rad = 50
3750 shape = star (num_points = 5 )
38- path = sinusoidal_ring (rad = 50 )
51+ path = sinusoidal_ring (rad = path_rad , segments = 240 )
52+
53+ # # If scale_factors aren't included, they'll default to
54+ # # no scaling at each step along path. Here, let's
55+ # # make the shape twice as big at beginning and end of the path
56+ # scales = [1] * len(path)
57+ # n = len(path)
58+ # scales = [1 + 0.5*sin(i*6*pi/n) for i in range(n)]
59+ # scales[0] = 2
60+ # scales[-1] = 2
61+
62+ extruded = extrude_along_path ( shape_pts = shape , path_pts = path )
63+ # Label
64+ extruded += translate ([- path_rad / 2 , 2 * path_rad ])(text ('Basic Extrude' ))
65+ return extruded
66+
67+ def extrude_example_xy_scaling () -> OpenSCADObject :
68+ num_points = SEGMENTS
69+ path_rad = 50
70+ circle = circle_points (15 )
71+ path = circle_points (rad = path_rad )
72+
73+ # angle: from 0 to 6*Pi
74+ angles = list ((i / (num_points - 1 )* tau * 3 for i in range (len (path ))))
75+
3976
4077 # If scale_factors aren't included, they'll default to
41- # no scaling at each step along path. Here, let's
42- # make the shape twice as big at beginning and end of the path
43- scales = [1 ] * len (path )
44- scales [0 ] = 2
45- scales [- 1 ] = 2
78+ # no scaling at each step along path.
79+ no_scale_obj = translate ([- path_rad / 2 , 2 * path_rad ])(text ('No Scale' ))
80+ no_scale_obj += extrude_along_path (circle , path )
4681
47- extruded = extrude_along_path (shape_pts = shape , path_pts = path , scale_factors = scales )
82+ # With a 1-D scale factor, an extrusion grows and shrinks uniformly
83+ x_scales = [(1 + cos (a )/ 2 ) for a in angles ]
84+ x_obj = translate ([- path_rad / 2 , 2 * path_rad ])(text ('1D Scale' ))
85+ x_obj += extrude_along_path (circle , path , scale_factors = x_scales )
4886
49- return extruded
87+ # With a 2D scale factor, a shape's X & Y dimensions can scale
88+ # independently, leading to more interesting shapes
89+ # X & Y scales vary between 0.5 & 1.5
90+ xy_scales = [Point2 ( 1 + cos (a )/ 2 , 1 + sin (a )/ 2 ) for a in angles ]
91+ xy_obj = translate ([- path_rad / 2 , 2 * path_rad ])( text ('2D Scale' ))
92+ xy_obj += extrude_along_path (circle , path , scale_factors = xy_scales )
93+
94+ obj = no_scale_obj + right (3 * path_rad )(x_obj ) + right (6 * path_rad )(xy_obj )
95+ return obj
5096
97+ if __name__ == "__main__" :
98+ out_dir = sys .argv [1 ] if len (sys .argv ) > 1 else Path (__file__ ).parent
5199
52- if __name__ == '__main__' :
53- out_dir = sys . argv [ 1 ] if len ( sys . argv ) > 1 else None
54- a = extrude_example ( )
55- file_out = scad_render_to_file (a , out_dir = out_dir , include_orig_code = True )
100+ basic_extrude = extrude_example ()
101+ scaled_extrusions = extrude_example_xy_scaling ()
102+ a = basic_extrude + translate ([ 0 , - 250 ])( scaled_extrusions )
103+ file_out = scad_render_to_file (a , out_dir = out_dir , include_orig_code = True )
56104 print (f"{ __file__ } : SCAD file written to: \n { file_out } " )
0 commit comments