├── LICENSE.txt
├── README.md
├── images
└── smooth_prim.png
└── smooth_prim.scad
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Creative Commons Legal Code
2 |
3 | CC0 1.0 Universal
4 |
5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
12 | HEREUNDER.
13 |
14 | Statement of Purpose
15 |
16 | The laws of most jurisdictions throughout the world automatically confer
17 | exclusive Copyright and Related Rights (defined below) upon the creator
18 | and subsequent owner(s) (each and all, an "owner") of an original work of
19 | authorship and/or a database (each, a "Work").
20 |
21 | Certain owners wish to permanently relinquish those rights to a Work for
22 | the purpose of contributing to a commons of creative, cultural and
23 | scientific works ("Commons") that the public can reliably and without fear
24 | of later claims of infringement build upon, modify, incorporate in other
25 | works, reuse and redistribute as freely as possible in any form whatsoever
26 | and for any purposes, including without limitation commercial purposes.
27 | These owners may contribute to the Commons to promote the ideal of a free
28 | culture and the further production of creative, cultural and scientific
29 | works, or to gain reputation or greater distribution for their Work in
30 | part through the use and efforts of others.
31 |
32 | For these and/or other purposes and motivations, and without any
33 | expectation of additional consideration or compensation, the person
34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she
35 | is an owner of Copyright and Related Rights in the Work, voluntarily
36 | elects to apply CC0 to the Work and publicly distribute the Work under its
37 | terms, with knowledge of his or her Copyright and Related Rights in the
38 | Work and the meaning and intended legal effect of CC0 on those rights.
39 |
40 | 1. Copyright and Related Rights. A Work made available under CC0 may be
41 | protected by copyright and related or neighboring rights ("Copyright and
42 | Related Rights"). Copyright and Related Rights include, but are not
43 | limited to, the following:
44 |
45 | i. the right to reproduce, adapt, distribute, perform, display,
46 | communicate, and translate a Work;
47 | ii. moral rights retained by the original author(s) and/or performer(s);
48 | iii. publicity and privacy rights pertaining to a person's image or
49 | likeness depicted in a Work;
50 | iv. rights protecting against unfair competition in regards to a Work,
51 | subject to the limitations in paragraph 4(a), below;
52 | v. rights protecting the extraction, dissemination, use and reuse of data
53 | in a Work;
54 | vi. database rights (such as those arising under Directive 96/9/EC of the
55 | European Parliament and of the Council of 11 March 1996 on the legal
56 | protection of databases, and under any national implementation
57 | thereof, including any amended or successor version of such
58 | directive); and
59 | vii. other similar, equivalent or corresponding rights throughout the
60 | world based on applicable law or treaty, and any national
61 | implementations thereof.
62 |
63 | 2. Waiver. To the greatest extent permitted by, but not in contravention
64 | of, applicable law, Affirmer hereby overtly, fully, permanently,
65 | irrevocably and unconditionally waives, abandons, and surrenders all of
66 | Affirmer's Copyright and Related Rights and associated claims and causes
67 | of action, whether now known or unknown (including existing as well as
68 | future claims and causes of action), in the Work (i) in all territories
69 | worldwide, (ii) for the maximum duration provided by applicable law or
70 | treaty (including future time extensions), (iii) in any current or future
71 | medium and for any number of copies, and (iv) for any purpose whatsoever,
72 | including without limitation commercial, advertising or promotional
73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
74 | member of the public at large and to the detriment of Affirmer's heirs and
75 | successors, fully intending that such Waiver shall not be subject to
76 | revocation, rescission, cancellation, termination, or any other legal or
77 | equitable action to disrupt the quiet enjoyment of the Work by the public
78 | as contemplated by Affirmer's express Statement of Purpose.
79 |
80 | 3. Public License Fallback. Should any part of the Waiver for any reason
81 | be judged legally invalid or ineffective under applicable law, then the
82 | Waiver shall be preserved to the maximum extent permitted taking into
83 | account Affirmer's express Statement of Purpose. In addition, to the
84 | extent the Waiver is so judged Affirmer hereby grants to each affected
85 | person a royalty-free, non transferable, non sublicensable, non exclusive,
86 | irrevocable and unconditional license to exercise Affirmer's Copyright and
87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the
88 | maximum duration provided by applicable law or treaty (including future
89 | time extensions), (iii) in any current or future medium and for any number
90 | of copies, and (iv) for any purpose whatsoever, including without
91 | limitation commercial, advertising or promotional purposes (the
92 | "License"). The License shall be deemed effective as of the date CC0 was
93 | applied by Affirmer to the Work. Should any part of the License for any
94 | reason be judged legally invalid or ineffective under applicable law, such
95 | partial invalidity or ineffectiveness shall not invalidate the remainder
96 | of the License, and in such case Affirmer hereby affirms that he or she
97 | will not (i) exercise any of his or her remaining Copyright and Related
98 | Rights in the Work or (ii) assert any associated claims and causes of
99 | action with respect to the Work, in either case contrary to Affirmer's
100 | express Statement of Purpose.
101 |
102 | 4. Limitations and Disclaimers.
103 |
104 | a. No trademark or patent rights held by Affirmer are waived, abandoned,
105 | surrendered, licensed or otherwise affected by this document.
106 | b. Affirmer offers the Work as-is and makes no representations or
107 | warranties of any kind concerning the Work, express, implied,
108 | statutory or otherwise, including without limitation warranties of
109 | title, merchantability, fitness for a particular purpose, non
110 | infringement, or the absence of latent or other defects, accuracy, or
111 | the present or absence of errors, whether or not discoverable, all to
112 | the greatest extent permissible under applicable law.
113 | c. Affirmer disclaims responsibility for clearing rights of other persons
114 | that may apply to the Work or any use thereof, including without
115 | limitation any person's Copyright and Related Rights in the Work.
116 | Further, Affirmer disclaims responsibility for obtaining any necessary
117 | consents, permissions or other rights required for any use of the
118 | Work.
119 | d. Affirmer understands and acknowledges that Creative Commons is not a
120 | party to this document and has no duty or obligation with respect to
121 | this CC0 or use of the Work.
122 |
123 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OpenSCAD smooth primitives library
2 |
3 |

4 |
5 | This library is a collection of some smooth primitives, i.e. having specified
6 | rounded edges, for use in other designs. It's not a comprehensive collection,
7 | but a useful set.
8 |
9 | * SmoothCylinder
10 | * HollowCylinder
11 | * SmoothHole
12 | * ChamferHole
13 | * SmoothCube
14 | * SmoothXYCube
15 | * SmoothCorner
16 | * SmoothWall
17 | * SmoothHollowCube
18 | * CutCorner
19 | * CutCube
20 |
21 |
22 |
--------------------------------------------------------------------------------
/images/smooth_prim.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rcolyer/smooth-prim/0d0038f984465f3eb0f6026a4d5de2f79d2dcea8/images/smooth_prim.png
--------------------------------------------------------------------------------
/smooth_prim.scad:
--------------------------------------------------------------------------------
1 | // Created in 2016-2019 by Ryan A. Colyer.
2 | // This work is released with CC0 into the public domain.
3 | // https://creativecommons.org/publicdomain/zero/1.0/
4 |
5 |
6 | module SmoothCylinder(radius, height, smooth_rad) {
7 | $fa = ($fa >= 12) ? 1 : $fa;
8 | $fs = ($fs >= 2) ? 0.4 : $fs;
9 |
10 | if (radius > smooth_rad) {
11 | rotate_extrude(convexity=10)
12 | hull() {
13 | square([radius-smooth_rad, height]);
14 | intersection() {
15 | translate([0, -0.1*height])
16 | square([1.1*radius, 1.2*height]);
17 | union() {
18 | translate([radius-smooth_rad, smooth_rad])
19 | circle(r=smooth_rad);
20 | translate([radius-smooth_rad, height-smooth_rad])
21 | circle(r=smooth_rad);
22 | }
23 | }
24 | }
25 | }
26 | else {
27 | rotate_extrude(convexity=10)
28 | hull() {
29 | intersection() {
30 | translate([0, -0.1*height])
31 | square([1.1*radius, 1.2*height]);
32 | union() {
33 | translate([0, radius])
34 | circle(r=radius);
35 | translate([0, height-radius])
36 | circle(r=radius);
37 | }
38 | }
39 | }
40 | }
41 | }
42 |
43 |
44 | module HollowCylinder(outer_rad, inner_rad, height) {
45 | $fa = ($fa >= 12) ? 1 : $fa;
46 | $fs = ($fs >= 2) ? 0.4 : $fs;
47 |
48 | rad_diff = outer_rad-inner_rad;
49 | rotate_extrude(convexity=10)
50 | translate([(outer_rad+inner_rad)/2, 0, 0])
51 | hull() {
52 | translate([0, rad_diff/2, 0])
53 | circle(r=rad_diff/2);
54 | translate([0, height-rad_diff/2, 0])
55 | circle(r=rad_diff/2);
56 | }
57 | }
58 |
59 | module SmoothHole(radius, height, smooth_rad,
60 | position=[0,0,0], rotation=[0,0,0]) {
61 | $fa = ($fa >= 12) ? 1 : $fa;
62 | $fs = ($fs >= 2) ? 0.4 : $fs;
63 |
64 | extra_height = 0.002 * height;
65 |
66 | difference() {
67 | children();
68 | translate(position)
69 | rotate(rotation)
70 | translate([0, 0, -extra_height/2])
71 | difference() {
72 | translate([0, 0, -extra_height])
73 | cylinder(r=radius+smooth_rad, h=height+2*extra_height);
74 | HollowCylinder(radius+2*smooth_rad, radius, height+extra_height);
75 | }
76 | }
77 | }
78 |
79 |
80 | module ChamferHole(radius, height, chamfer_size,
81 | position=[0,0,0], rotation=[0,0,0]) {
82 | $fa = ($fa >= 12) ? 1 : $fa;
83 | $fs = ($fs >= 2) ? 0.4 : $fs;
84 |
85 | cham = chamfer_size < height/2 - 0.001 ? chamfer_size : height/2 - 0.001;
86 | extra_height = 0.002 * height;
87 | height_ex = height+extra_height;
88 |
89 | difference() {
90 | children();
91 | translate(position)
92 | rotate(rotation)
93 | translate([0, 0, -extra_height/2])
94 | rotate_extrude()
95 | polygon([[0,0], [0,height_ex], [radius+cham,height_ex],
96 | [radius,height_ex-cham], [radius,cham],
97 | [radius+cham,0]]);
98 | }
99 | }
100 |
101 |
102 | module SmoothCube(size, smooth_rad) {
103 | $fa = ($fa >= 12) ? 1 : $fa;
104 | $fs = ($fs >= 2) ? 0.4 : $fs;
105 |
106 | size = is_num(size) ? [size, size, size] : size;
107 | smooth_rad = is_num(smooth_rad) ? [smooth_rad, smooth_rad, smooth_rad] :
108 | smooth_rad;
109 | smooth_base = smooth_rad[0];
110 | scales = smooth_rad / smooth_base;
111 |
112 | scalex = scales[0] * ((smooth_rad[0] < size[0]/2) ? 1 : size[0]/(2*smooth_rad[0]));
113 | scaley = scales[1] * ((smooth_rad[1] < size[1]/2) ? 1 : size[1]/(2*smooth_rad[1]));
114 | scalez = scales[2] * ((smooth_rad[2] < size[2]/2) ? 1 : size[2]/(2*smooth_rad[2]));
115 | smoothx = smooth_rad[0] * scalex / scales[0];
116 | smoothy = smooth_rad[1] * scaley / scales[1];
117 | smoothz = smooth_rad[2] * scalez / scales[2];
118 |
119 | hull() {
120 | translate([smoothx, smoothy, smoothz])
121 | scale([scalex, scaley, scalez])
122 | sphere(r=smooth_base);
123 | translate([size[0]-smoothx, smoothy, smoothz])
124 | scale([scalex, scaley, scalez])
125 | sphere(r=smooth_base);
126 | translate([smoothx, size[1]-smoothy, smoothz])
127 | scale([scalex, scaley, scalez])
128 | sphere(r=smooth_base);
129 | translate([smoothx, smoothy, size[2]-smoothz])
130 | scale([scalex, scaley, scalez])
131 | sphere(r=smooth_base);
132 | translate([size[0]-smoothx, size[1]-smoothy, smoothz])
133 | scale([scalex, scaley, scalez])
134 | sphere(r=smooth_base);
135 | translate([size[0]-smoothx, smoothy, size[2]-smoothz])
136 | scale([scalex, scaley, scalez])
137 | sphere(r=smooth_base);
138 | translate([smoothx, size[1]-smoothy, size[2]-smoothz])
139 | scale([scalex, scaley, scalez])
140 | sphere(r=smooth_base);
141 | translate([size[0]-smoothx, size[1]-smoothy, size[2]-smoothz])
142 | scale([scalex, scaley, scalez])
143 | sphere(r=smooth_base);
144 | }
145 | }
146 |
147 |
148 | module SmoothXYCube(size, smooth_rad) {
149 | $fa = ($fa >= 12) ? 1 : $fa;
150 | $fs = ($fs >= 2) ? 0.4 : $fs;
151 |
152 | size = is_num(size) ? [size, size, size] : size;
153 |
154 | scalex = (smooth_rad < size[0]/2) ? 1 : size[0]/(2*smooth_rad);
155 | scaley = (smooth_rad < size[1]/2) ? 1 : size[1]/(2*smooth_rad);
156 | smoothx = smooth_rad * scalex;
157 | smoothy = smooth_rad * scaley;
158 |
159 | linear_extrude(size[2]) hull() {
160 | translate([smoothx, smoothy])
161 | scale([scalex, scaley])
162 | circle(r=smooth_rad);
163 | translate([size[0]-smoothx, smoothy])
164 | scale([scalex, scaley])
165 | circle(r=smooth_rad);
166 | translate([smoothx, size[1]-smoothy])
167 | scale([scalex, scaley])
168 | circle(r=smooth_rad);
169 | translate([size[0]-smoothx, size[1]-smoothy])
170 | scale([scalex, scaley])
171 | circle(r=smooth_rad);
172 | }
173 | }
174 |
175 |
176 | module SmoothCorner(height, width, inner_curv=0) {
177 | $fa = ($fa >= 12) ? 1 : $fa;
178 | $fs = ($fs >= 2) ? 0.4 : $fs;
179 |
180 | translate([width+inner_curv, width+inner_curv, 0])
181 | rotate([0, 0, 180])
182 | rotate_extrude(angle=90, convexity=10)
183 | translate([width/2+inner_curv, 0, 0])
184 | hull() {
185 | translate([0, width/2, 0])
186 | circle(r=width/2);
187 | translate([0, height-width/2, 0])
188 | circle(r=width/2);
189 | }
190 | }
191 |
192 |
193 | module SmoothWall(width, height, wall_width) {
194 | $fa = ($fa >= 12) ? 1 : $fa;
195 | $fs = ($fs >= 2) ? 0.4 : $fs;
196 |
197 | rotate([-90, 180, -90])
198 | linear_extrude(width)
199 | translate([wall_width/2, 0, 0])
200 | hull() {
201 | translate([0, wall_width/2, 0])
202 | circle(r=wall_width/2);
203 | translate([0, height-wall_width/2, 0])
204 | circle(r=wall_width/2);
205 | }
206 | }
207 |
208 |
209 | module SmoothHollowCube(size, wall_width, inner_curv=0) {
210 | $fa = ($fa >= 12) ? 1 : $fa;
211 | $fs = ($fs >= 2) ? 0.4 : $fs;
212 |
213 | size = is_num(size) ? [size, size, size] : size;
214 |
215 | min_ww_size = min(size[0]/2, size[1]/2, size[2]);
216 | wall_width = wall_width < min_ww_size ? wall_width : min_ww_size;
217 | max_inner_curv = (min(size[0], size[1])-2*wall_width)/2;
218 | inner_curv = inner_curv < max_inner_curv ? inner_curv : max_inner_curv;
219 |
220 | SmoothCorner(size[2], wall_width, inner_curv);
221 | translate([size[0], 0, 0])
222 | rotate([0, 0, 90])
223 | SmoothCorner(size[2], wall_width, inner_curv);
224 | translate([size[0], size[1], 0])
225 | rotate([0, 0, 180])
226 | SmoothCorner(size[2], wall_width, inner_curv);
227 | translate([0, size[1], 0])
228 | rotate([0, 0, 270])
229 | SmoothCorner(size[2], wall_width, inner_curv);
230 |
231 | wall_lengthx = size[0]-2*wall_width-2*inner_curv+0.002;
232 | wall_lengthy = size[1]-2*wall_width-2*inner_curv+0.002;
233 | wall_height = size[2];
234 |
235 | translate([size[0], wall_width+inner_curv-0.001, 0])
236 | rotate([0, 0, 90])
237 | SmoothWall(wall_lengthy, wall_height, wall_width);
238 | translate([wall_width, wall_width+inner_curv-0.001, 0])
239 | rotate([0, 0, 90])
240 | SmoothWall(wall_lengthy, wall_height, wall_width);
241 | translate([wall_width+inner_curv-0.001, 0, 0])
242 | SmoothWall(wall_lengthx, wall_height, wall_width);
243 | translate([wall_width+inner_curv-0.001, size[1]-wall_width, 0])
244 | SmoothWall(wall_lengthx, wall_height, wall_width);
245 | }
246 |
247 |
248 | module CutCorner(insetby, cornerpos=[0,0,0], positives=[undef,undef,undef]) {
249 | clearance = 4*insetby + 0.001;
250 | positives = positives==[undef,undef,undef] ? cornerpos : positives;
251 | angle_offset = (positives[0]?90:0) + (positives[1]?-90:0)
252 | + ((positives[0]&&positives[1])?180:0);
253 |
254 | difference() {
255 | children();
256 | translate(cornerpos)
257 | rotate([0, 0, 225+angle_offset])
258 | rotate([0, positives[2]?-45:45, 0])
259 | translate([-insetby, -clearance/2, -clearance/2])
260 | cube([clearance, clearance, clearance]);
261 | }
262 | }
263 |
264 | module CutCube(size, insetby=0) {
265 | size = is_num(size) ? [size, size, size] : size;
266 |
267 | CutCorner(insetby, [0,0,0])
268 | CutCorner(insetby, [0,0,size[2]])
269 | CutCorner(insetby, [0,size[1],0])
270 | CutCorner(insetby, [0,size[1],size[2]])
271 | CutCorner(insetby, [size[0],0,0])
272 | CutCorner(insetby, [size[0],0,size[2]])
273 | CutCorner(insetby, [size[0],size[1],0])
274 | CutCorner(insetby, [size[0],size[1],size[2]])
275 | cube(size);
276 | }
277 |
278 |
279 |
280 | module Demo() {
281 | translate([0, -50, 0])
282 | HollowCylinder(22, 20, 10);
283 |
284 | SmoothHole(5, 10, 2)
285 | SmoothCylinder(22, 10, 2);
286 |
287 | translate([30, -30, 0]) SmoothCube([10, 14, 18], 2);
288 |
289 | translate([50, 0, 0]) CutCube([15, 14, 18], 3);
290 |
291 | translate([30, 0, 0]) SmoothXYCube([10, 14, 18], 2);
292 |
293 | translate([57, -23, 0]) SmoothCylinder(5, 18, 2);
294 |
295 | translate([35, -60, 0]) SmoothHollowCube([22, 20, 14], 3, 2);
296 |
297 | translate([80, 0, 0])
298 | ChamferHole(4, 10, 2, [10, 10, 0])
299 | cube([20, 20, 10]);
300 | }
301 |
302 |
303 | Demo();
304 |
305 |
306 |
--------------------------------------------------------------------------------