mirror of
https://github.com/Irev-Dev/Round-Anything.git
synced 2025-09-03 04:12:38 +02:00
Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
061fef7c42 | ||
|
2f47c7631c | ||
|
57c7889ff0 | ||
|
0161f336e0 | ||
|
980948b31c | ||
|
d4a001ce09 | ||
|
116c961393 | ||
|
5711ff827c | ||
|
dd7d7121c0 | ||
|
ea20000c74 | ||
|
df71daa0cb | ||
|
23a4204593 | ||
|
ba1e80058c | ||
|
0fbca7c2d5 | ||
|
dd05f2e441 | ||
|
f35262f955 | ||
|
1b7623e17b | ||
|
c56190a81b | ||
|
e9faa0785d | ||
|
e9d3d805ab | ||
|
df50ac47ce | ||
|
9c2e9b929b | ||
|
cfd739d79d | ||
|
f69ddaa05b | ||
|
bce6705d4c | ||
|
28814a34a0 | ||
|
8ead00a2bf | ||
|
66f30bed93 | ||
|
f9928e36e1 | ||
|
26fb282626 | ||
|
c04a81f25c | ||
|
e6d91c352b | ||
|
297a7ce5dc | ||
|
a6999a7202 | ||
|
a85e6ffd48 | ||
|
5a7b6db0ec | ||
|
6b16407430 | ||
|
9613a81f15 | ||
|
e6d67b6304 | ||
|
8d5b6a180b | ||
|
0697444270 | ||
|
764b3b7a73 | ||
|
a3934972b5 | ||
|
cb9e7f7b30 | ||
|
1f15acb04b | ||
|
ddbb97b5ee | ||
|
40a14892f2 |
22
README.md
22
README.md
@@ -6,14 +6,27 @@ Round-Anything is primarily a set of OpenSCAD utilities that help with rounding
|
||||
|
||||
## The Why
|
||||
|
||||
The truth is radii, internal radii in particular can be a real pain to add in openscad. and the more you move away from shapes with 90 degree angles the more difficult it becomes, effectively puting a complexity ceiling on parts you can produce in OpenScad. Because of how important radii in both making a apealing and strong part, reducing stress concentration etc, A library that focuses on radii as a core principle makes for a solid foundation for your parts. Furthermore the heart of the library revolves around the polygon, this is because we're leveraging the battle tested paradigm of extruding from 2d sketches of most CAD packages. I can't imagine making an OpenScad part without Round-Anything.
|
||||
The truth is radii, internal radii in particular can be a real pain to add in openscad. and the more you move away from shapes with 90 degree angles the more difficult it becomes, effectively putting a complexity ceiling on parts you can produce in OpenScad. Because of how important radii in both making an appealing and strong part, reducing stress concentration etc, A library that focuses on radii as a core principle makes for a solid foundation for your parts. Furthermore the heart of the library revolves around the polygon, this is because we're leveraging the battle tested paradigm of extruding from 2d sketches of most CAD packages. I can't imagine making an OpenScad part without Round-Anything.
|
||||
|
||||
### Quick side-notes
|
||||
|
||||
I'm currently working on a community website for "Code-CAD" (like OpenSCAD). A good way to think of it is codepen crossed with a thing repository. You can check it out at [cadhub.xyz](https://cadhub.xyz/) or it's [repo](https://github.com/Irev-Dev/cadhub).
|
||||
|
||||
Also please submit examples of what you build with the library in the [discussions](https://github.com/Irev-Dev/Round-Anything/discussions), I'd love to see them. I also recommend you "watch" the repo with notifications turned on for the discussions to stay up-to-date.
|
||||
|
||||
## Documentation
|
||||
|
||||
[Here is an overview of the library's features](https://kurthutten.com/blog/round-anything-a-pragmatic-approach-to-openscad-design/).
|
||||
See an overview of the library in [video form](https://www.youtube.com/watch?v=laxv2wFKq8Q)
|
||||
|
||||
<a href="https://www.youtube.com/watch?v=laxv2wFKq8Q"><img src="https://i.ytimg.com/vi/laxv2wFKq8Q/sddefault.jpg" width="100%" align="left"></a>
|
||||
|
||||
|
||||
[Written overview](https://kurthutten.com/blog/round-anything-a-pragmatic-approach-to-openscad-design/).
|
||||
|
||||
[Full documentation of the API is here](https://kurthutten.com/blog/round-anything-api/).
|
||||
|
||||
[Installation instructions](https://github.com/Irev-Dev/Round-Anything/discussions/21)
|
||||
|
||||
## Extra
|
||||
|
||||
I [live streamed](https://www.youtube.com/watch?v=1Tegarwy69I&t=2s) the making of [this part](https://github.com/Irev-Dev/monitor-stand-turn-camera) using this library. I was able to make the bulk of this part quickly even with some complex radii involved thanks to the library.
|
||||
@@ -23,3 +36,8 @@ I [live streamed](https://www.youtube.com/watch?v=1Tegarwy69I&t=2s) the making o
|
||||
Below are some of the example parts that can be found in [roundAnythingExamples.scad](https://github.com/Irev-Dev/Round-Anything/blob/master/roundAnythingExamples.scad).
|
||||
|
||||
<img src="https://cdn.sanity.io/images/2hqqc7om/production/2dba6301d1f25b1c45a634058b280b52fa713b60-1920x1080.png?w=1920&h=1000&fit=crop" width="100%" align="left">
|
||||
|
||||
## Citation
|
||||
roundUnionMask Includes code based on examples from:
|
||||
Kogan, Jonathan (2017) "A New Computationally Efficient Method for Spacing n Points on a Sphere," Rose-Hulman Undergraduate Mathematics Journal: Vol. 18 : Iss. 2 , Article 5.
|
||||
Available at: [https://scholar.rose-hulman.edu/rhumj/vol18/iss2/5]
|
||||
|
3
examples/README.md
Normal file
3
examples/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Round-Anything examples
|
||||
|
||||
These examples are mostly to go with the [library Documentation](https://learn.cadhub.xyz/docs/round-anything/overview) and so are best viewed there.
|
34
examples/beamChain-1.scad
Normal file
34
examples/beamChain-1.scad
Normal file
@@ -0,0 +1,34 @@
|
||||
// beamChain example 1
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
function beamPoints(r1,r2,rStart=0,rEnd=0)=[
|
||||
[0, 0, rStart],
|
||||
[2, 8, 0 ],
|
||||
[5, 4, r1 ],
|
||||
[15, 10, r2 ],
|
||||
[17, 2, rEnd ]
|
||||
];
|
||||
|
||||
linear_extrude(1){
|
||||
|
||||
// chained lines by themselves
|
||||
translate(){
|
||||
radiiPoints=beamPoints(0,0);
|
||||
polygon(polyRound(beamChain(radiiPoints,offset1=0.02, offset2=-0.02),20));
|
||||
}
|
||||
|
||||
|
||||
// Add some radii to the line transitions
|
||||
translate([0,-7,0]){
|
||||
radiiPoints=beamPoints(2,1);
|
||||
polygon(polyRound(beamChain(radiiPoints,offset1=0.02, offset2=-0.02),20));
|
||||
}
|
||||
|
||||
// Give make the lines beams with some thickness
|
||||
translate([0,-7*2,0]){
|
||||
radiiPoints=beamPoints(2,1);
|
||||
polygon(polyRound(beamChain(radiiPoints,offset1=0.5, offset2=-0.5),20));
|
||||
}
|
||||
|
||||
}
|
27
examples/beamChain-2.scad
Normal file
27
examples/beamChain-2.scad
Normal file
@@ -0,0 +1,27 @@
|
||||
// beamChain example 2
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
function beamPoints(r1,r2,rStart=0,rEnd=0)=[
|
||||
[0, 0, rStart],
|
||||
[2, 8, 0 ],
|
||||
[5, 4, r1 ],
|
||||
[15, 10, r2 ],
|
||||
[17, 2, rEnd ]
|
||||
];
|
||||
|
||||
linear_extrude(1){
|
||||
|
||||
// Add an angle to the start of the beam
|
||||
translate([0,-7*3,0]){
|
||||
radiiPoints=beamPoints(2,1);
|
||||
polygon(polyRound(beamChain(radiiPoints,offset1=0.5, offset2=-0.5, startAngle=45),20));
|
||||
}
|
||||
|
||||
// Put a negative radius at the start for transationing to a flat surface
|
||||
translate([0,-7*4,0]){
|
||||
radiiPoints=beamPoints(2,1,rStart=-0.7);
|
||||
polygon(polyRound(beamChain(radiiPoints,offset1=0.5, offset2=-0.5, startAngle=45),20));
|
||||
}
|
||||
|
||||
}
|
50
examples/beamChain-3.scad
Normal file
50
examples/beamChain-3.scad
Normal file
@@ -0,0 +1,50 @@
|
||||
// beamChain example 3
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
function beamPoints(r1,r2,rStart=0,rEnd=0)=[
|
||||
[0, 0, rStart],
|
||||
[2, 8, 0 ],
|
||||
[5, 4, r1 ],
|
||||
[15, 10, r2 ],
|
||||
[17, 2, rEnd ]
|
||||
];
|
||||
|
||||
// Define more points for a polygon to be atteched to the end of the beam chain
|
||||
clipP=[
|
||||
[16, 1.2, 0 ],
|
||||
[16, 0, 0 ],
|
||||
[16.5, 0, 0 ],
|
||||
[16.5, 1, 0.2],
|
||||
[17.5, 1, 0.2],
|
||||
[17.5, 0, 0 ],
|
||||
[18, 0, 0 ],
|
||||
[18, 1.2, 0 ]
|
||||
];
|
||||
|
||||
linear_extrude(1){
|
||||
// end hook
|
||||
translate([-15,-7*5+3,0]){
|
||||
polygon(polyRound(clipP,20));
|
||||
}
|
||||
|
||||
// Attached to the end of the beam chain by dividing the beam paths in forward and return and
|
||||
// concat other polygon inbetween
|
||||
translate([0,-7*6,0]){
|
||||
radiiPoints=beamPoints(2,1);
|
||||
forwardPath=beamChain(radiiPoints,offset1=0.5,startAngle=-15,mode=2);
|
||||
returnPath=revList(beamChain(radiiPoints,offset1=-0.5,startAngle=-15,mode=2));
|
||||
entirePath=concat(forwardPath,clipP,returnPath);
|
||||
polygon(polyRound(entirePath,20));
|
||||
}
|
||||
|
||||
// Add transitioning radii into the end polygong
|
||||
translate([0,-7*7-2,0]){
|
||||
radiiPoints=beamPoints(2,1,rEnd=3);
|
||||
forwardPath=beamChain(radiiPoints,offset1=0.5,startAngle=-15,mode=2);
|
||||
returnPath=revList(beamChain(radiiPoints,offset1=-0.5,startAngle=-15,mode=2));
|
||||
entirePath=concat(forwardPath,clipP,returnPath);
|
||||
polygon(polyRound(entirePath,20));
|
||||
}
|
||||
|
||||
}
|
22
examples/beamChain-4.scad
Normal file
22
examples/beamChain-4.scad
Normal file
@@ -0,0 +1,22 @@
|
||||
// beamChain example 4
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
function beamPoints(r1,r2,rStart=0,rEnd=0)=[
|
||||
[0, 0, rStart],
|
||||
[2, 8, 0 ],
|
||||
[5, 4, r1 ],
|
||||
[15, 10, r2 ],
|
||||
[17, 2, rEnd ]
|
||||
];
|
||||
|
||||
linear_extrude(1){
|
||||
|
||||
translate([0,-7*9,0]){
|
||||
// Define multiple shells from the the one set of points
|
||||
for(i=[0:2]){
|
||||
polygon(polyRound(beamChain(beamPoints(2,1),offset1=-1+i*0.4, offset2=-1+i*0.4+0.25),20));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
13
examples/extrudeWithRadius.scad
Normal file
13
examples/extrudeWithRadius.scad
Normal file
@@ -0,0 +1,13 @@
|
||||
// extrudeWithRadius example
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
radiiPoints=[
|
||||
[-4, 0, 1 ],
|
||||
[5, 3, 1.5 ],
|
||||
[0, 7, 0.1 ],
|
||||
[8, 7, 10 ],
|
||||
[20, 20, 0.8 ],
|
||||
[10, 0, 10 ]
|
||||
];
|
||||
extrudeWithRadius(3,0.5,0.5,5)polygon(polyRound(radiiPoints,30));
|
10
examples/mirrorPoints.scad
Normal file
10
examples/mirrorPoints.scad
Normal file
@@ -0,0 +1,10 @@
|
||||
// mirrorPoints example
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
centerRadius=7;
|
||||
points=[[0,0,0],[2,8,0],[5,4,3],[15,10,0.5],[10,2,centerRadius]];
|
||||
mirroredPoints=mirrorPoints(points,0,[0,0]);
|
||||
linear_extrude(1)
|
||||
translate([0,-20,0])
|
||||
polygon(polyRound(mirroredPoints,20));
|
24
examples/negative-polyRoundExtrude.scad
Normal file
24
examples/negative-polyRoundExtrude.scad
Normal file
@@ -0,0 +1,24 @@
|
||||
// negative polyRoundExtrude example
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
extrudeRadius = 0.8;
|
||||
extrudeHeight = 2;
|
||||
tiny = 0.005; // tiny value is used to stop artifacts from planes lining up perfectly
|
||||
|
||||
radiiPoints=[
|
||||
[-7, -3, 0 ],
|
||||
[7, -3, 0 ],
|
||||
[0, 6, 1 ] // top of the triagle is rounded
|
||||
];
|
||||
negativeRadiiPoints=[
|
||||
[-3, -1, 0 ],
|
||||
[3, -1, 0 ],
|
||||
[0, 3, 1 ] // top of the triagle is rounded
|
||||
];
|
||||
|
||||
difference() {
|
||||
polyRoundExtrude(radiiPoints,extrudeHeight, extrudeRadius, extrudeRadius,fn=20);
|
||||
translate([0,0,-tiny])
|
||||
polyRoundExtrude(negativeRadiiPoints,extrudeHeight+2*tiny, -extrudeRadius, -extrudeRadius,fn=20);
|
||||
}
|
13
examples/polyRoundExtrude.scad
Normal file
13
examples/polyRoundExtrude.scad
Normal file
@@ -0,0 +1,13 @@
|
||||
// polyRoundExtrude example
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
radiiPoints=[
|
||||
[10, 0, 10 ],
|
||||
[20, 20, 1.1],
|
||||
[8, 7, 10 ],
|
||||
[0, 7, 0.3],
|
||||
[5, 3, 0.1],
|
||||
[-4, 0, 1 ]
|
||||
];
|
||||
polyRoundExtrude(radiiPoints,2,0.5,-0.8,fn=20);
|
13
examples/polyround.scad
Normal file
13
examples/polyround.scad
Normal file
@@ -0,0 +1,13 @@
|
||||
// polyRound example
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
radiiPoints=[
|
||||
[-4, 0, 1 ],
|
||||
[5, 3, 1.5 ],
|
||||
[0, 7, 0.1 ],
|
||||
[8, 7, 10 ],
|
||||
[20, 20, 0.8 ],
|
||||
[10, 0, 10 ]
|
||||
];
|
||||
linear_extrude(3)polygon(polyRound(radiiPoints,30));
|
25
examples/radii-conflict.scad
Normal file
25
examples/radii-conflict.scad
Normal file
@@ -0,0 +1,25 @@
|
||||
// radii conflict example
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
//example of radii conflict handling and debuging feature
|
||||
function makeRadiiPoints(r1, r2)=[
|
||||
[0, 0, 0 ],
|
||||
[0, 20, r1 ],
|
||||
[20, 20, r2 ],
|
||||
[20, 0, 0 ]
|
||||
];
|
||||
|
||||
linear_extrude(3){
|
||||
// the squre shape being 20 wide, two radii of 10 both fit into the shape (just)
|
||||
translate([-25,0,0])polygon(polyRound(makeRadiiPoints(10,10),50));
|
||||
|
||||
//radii are too large and are reduced to fit and will be reduce to 10 and 10
|
||||
translate([0,0,0])polygon(polyRound(makeRadiiPoints(30,30),50));
|
||||
|
||||
//radii are too large again and are reduced to fit, but keep their ratios r1 will go from 10 to 4 and r2 will go from 40 to 16
|
||||
translate([25,0,0])polygon(polyRound(makeRadiiPoints(10,40),50));
|
||||
|
||||
//mode 2 = no radii limiting
|
||||
translate([50,0,0])polygon(polyRound(makeRadiiPoints(15,20),50,mode=2));
|
||||
}
|
29
examples/shell2d.scad
Normal file
29
examples/shell2d.scad
Normal file
@@ -0,0 +1,29 @@
|
||||
// shell2d example
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
module gridpattern(memberW = 4, sqW = 12, iter = 5, r = 3){
|
||||
round2d(0, r)rotate([0, 0, 45])translate([-(iter * (sqW + memberW) + memberW) / 2, -(iter * (sqW + memberW) + memberW) / 2])difference(){
|
||||
square([(iter) * (sqW + memberW) + memberW, (iter) * (sqW + memberW) + memberW]);
|
||||
for (i = [0:iter - 1], j = [0:iter - 1]){
|
||||
translate([i * (sqW + memberW) + memberW, j * (sqW + memberW) + memberW])square([sqW, sqW]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
radiiPoints=[
|
||||
[-4, 0, 1 ],
|
||||
[5, 3, 1.5 ],
|
||||
[0, 7, 0.1 ],
|
||||
[8, 7, 10 ],
|
||||
[20, 20, 0.8 ],
|
||||
[10, 0, 10 ]
|
||||
];
|
||||
|
||||
linear_extrude(1){
|
||||
shell2d(-0.5)polygon(polyRound(radiiPoints,30));
|
||||
translate([0,-10,0])shell2d(-0.5){
|
||||
polygon(polyRound(radiiPoints,30));
|
||||
translate([8,8])gridpattern(memberW = 0.3, sqW = 1, iter = 17, r = 0.2);
|
||||
}
|
||||
}
|
30
examples/translateRadiiPoints.scad
Normal file
30
examples/translateRadiiPoints.scad
Normal file
@@ -0,0 +1,30 @@
|
||||
// translateRadiiPoints example
|
||||
|
||||
include <Round-Anything-1.0.4/polyround.scad>
|
||||
|
||||
nutW=5.5; nutH=3; boltR=1.6;
|
||||
minT=2; minR=0.8;
|
||||
function nutCapture(startAndEndRadius=0)=[
|
||||
[-boltR, 0, startAndEndRadius],
|
||||
[-boltR, minT, 0],
|
||||
[-nutW/2, minT, minR],
|
||||
[-nutW/2, minT+nutH, minR],
|
||||
[nutW/2, minT+nutH, minR],
|
||||
[nutW/2, minT, minR],
|
||||
[boltR, minT, 0],
|
||||
[boltR, 0, startAndEndRadius],
|
||||
];
|
||||
linear_extrude(3)translate([-5,0,0])polygon(polyRound(nutCapture(),20));
|
||||
|
||||
negativeNutCapture=translateRadiiPoints(nutCapture(),tran=[5,0]);
|
||||
rotatedNegativeNutCapture=translateRadiiPoints(nutCapture(1),tran=[20,5],rot=90);
|
||||
aSquare=concat(
|
||||
[[0,0,0]],
|
||||
negativeNutCapture,
|
||||
[[20,0,0]],
|
||||
rotatedNegativeNutCapture,
|
||||
[[20,10,0]],
|
||||
[[0,10,0]]
|
||||
);
|
||||
|
||||
linear_extrude(3)polygon(polyRound(aSquare,20));
|
File diff suppressed because it is too large
Load Diff
228020
nicefillets.stl
228020
nicefillets.stl
File diff suppressed because it is too large
Load Diff
@@ -29,6 +29,11 @@ let(
|
||||
points[listWrap(i+1,lp)],
|
||||
],thick=offset,mode=isCWorCCW)];
|
||||
|
||||
function reverseList(list) = [ for(i=[len(list) - 1:-1:0]) list[i] ];
|
||||
|
||||
// Apply `reverseList` to the array of vertex indices for an array of faces
|
||||
function invertFaces(faces) = [ for(f=faces) reverseList(f) ];
|
||||
|
||||
function makeCurvedPartOfPolyHedron(radiiPoints,r,fn,minR=0.01)=
|
||||
// this is a private function that I'm not expecting library users to use directly
|
||||
// radiiPoints= serise of x, y, r points
|
||||
@@ -85,7 +90,7 @@ let(
|
||||
)
|
||||
[polyhedronPoints, polyhedronFaces, layerLength];
|
||||
|
||||
function flatternRecursion(array, init=[], currentIndex)=
|
||||
function flatternRecursion(array, init=[], currentIndex=0)=
|
||||
// this is a private function, init and currentIndex are for the function's use
|
||||
// only for when it's calling itself, which is why there is a simplified version flatternArray that just calls this one
|
||||
// array= array to flattern by one level of nesting
|
||||
@@ -129,7 +134,7 @@ function extrudePolygonWithRadius(radiiPoints,h=5,r1=1,r2=1,fn=4)=
|
||||
let(
|
||||
// top is the top curved part of the extrude
|
||||
top=makeCurvedPartOfPolyHedron(radiiPoints,r1,fn),
|
||||
topRadiusPoints=translate3Dcoords(top[0],[0,0,h-r1]),
|
||||
topRadiusPoints=translate3Dcoords(top[0],[0,0,h-abs(r1)]),
|
||||
singeLayerLength=top[2],
|
||||
topRadiusFaces=top[1],
|
||||
radiusPointsLength=len(topRadiusPoints), // is the same length as bottomRadiusPoints
|
||||
@@ -152,7 +157,7 @@ let(
|
||||
topCapFace=[for(i=[0:singeLayerLength-1])radiusPointsLength-singeLayerLength+i],
|
||||
bottomCapFace=[for(i=[0:singeLayerLength-1])radiusPointsLength*2-singeLayerLength+i],
|
||||
finalPolyhedronPoints=concat(topRadiusPoints,bottomRadiusPoints),
|
||||
finalPolyhedronFaces=concat(topRadiusFaces,bottomRadiusFaces, sideFaces, [topCapFace], [bottomCapFace])
|
||||
finalPolyhedronFaces=concat(topRadiusFaces,invertFaces(bottomRadiusFaces),invertFaces(sideFaces),[topCapFace],invertFaces([bottomCapFace]))
|
||||
)
|
||||
[
|
||||
finalPolyhedronPoints,
|
||||
@@ -160,8 +165,15 @@ let(
|
||||
];
|
||||
|
||||
module polyRoundExtrude(radiiPoints,length=5,r1=1,r2=1,fn=10,convexity=10) {
|
||||
polyhedronPointsNFaces=extrudePolygonWithRadius(radiiPoints,length,r1,r2,fn);
|
||||
polyhedron(points=polyhedronPointsNFaces[0], faces=polyhedronPointsNFaces[1], convexity=convexity);
|
||||
assert(len(radiiPoints) > 2, str("There must be at least 3 radii points for polyRoundExtrude. ", radiiPoints, " is not long enough, you need ", 3 - len(radiiPoints), " more point/s. Example: polyRoundExtrude([[11,0,1],[20,20,1.1],[8,7,0.5]],2,0.5,-0.8,fn=8);"));
|
||||
if(len(radiiPoints) > 2) {
|
||||
orderedRadiiPoints = CWorCCW(radiiPoints) == 1
|
||||
? reverseList(radiiPoints)
|
||||
: radiiPoints;
|
||||
|
||||
polyhedronPointsNFaces=extrudePolygonWithRadius(orderedRadiiPoints,length,r1,r2,fn);
|
||||
polyhedron(points=polyhedronPointsNFaces[0], faces=polyhedronPointsNFaces[1], convexity=convexity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -327,14 +339,22 @@ function parallelFollow(rp,thick=4,minR=1,mode=1)=
|
||||
)
|
||||
concat(cen,outR);
|
||||
|
||||
function is90or270(ang)=ang==90?1:ang==270?1:0;
|
||||
|
||||
function findPoint(ang1,refpoint1,ang2,refpoint2,r=0)=
|
||||
// finds the intersection of two lines given two angles and points on those lines
|
||||
let(
|
||||
overrideX=is90or270(ang1)?
|
||||
refpoint1.x:
|
||||
is90or270(ang2)?
|
||||
refpoint2.x:
|
||||
0,
|
||||
m1=tan(ang1),
|
||||
c1=refpoint1.y-m1*refpoint1.x,
|
||||
m2=tan(ang2),
|
||||
c2=refpoint2.y-m2*refpoint2.x,
|
||||
outputX=(c2-c1)/(m1-m2),
|
||||
outputY=m1*outputX+c1
|
||||
outputX=overrideX?overrideX:(c2-c1)/(m1-m2),
|
||||
outputY=is90or270(ang1)?m2*outputX+c2:m1*outputX+c1
|
||||
)
|
||||
[outputX,outputY,r];
|
||||
|
||||
@@ -374,13 +394,23 @@ function beamChain(radiiPoints,offset1=0,offset2,mode=0,minR=0,startAngle,endAng
|
||||
getAngle(radiiPoints[Lrp-1],radiiPoints[Lrp-2])+endAngle:
|
||||
endAngle,
|
||||
OffLn1=[for(i=[0:Lrp3]) offset1==0?radiiPoints[i+1]:parallelFollow([radiiPoints[i],radiiPoints[i+1],radiiPoints[i+2]],offset1,minR,mode=CWorCCW1)],
|
||||
OffLn2=[for(i=[0:Lrp3]) offset2==0?radiiPoints[i+1]:parallelFollow([radiiPoints[i],radiiPoints[i+1],radiiPoints[i+2]],offset2b,minR,mode=CWorCCW2)],
|
||||
OffLn2=[for(i=[0:Lrp3]) offset2==0?radiiPoints[i+1]:parallelFollow([radiiPoints[i],radiiPoints[i+1],radiiPoints[i+2]],offset2b,minR,mode=CWorCCW2)],
|
||||
|
||||
Rp1=abs(radiiPoints[0].z),
|
||||
Rp2=abs(radiiPoints[Lrp-1].z),
|
||||
endP1a=findPoint(getAngle(radiiPoints[0],radiiPoints[1]), OffLn1[0], startAngle,radiiPoints[0], Rp1),
|
||||
endP1b=findPoint(getAngle(radiiPoints[Lrp-1],radiiPoints[Lrp-2]), OffLn1[len(OffLn1)-1], endAngle,radiiPoints[Lrp-1], Rp2),
|
||||
endP2a=findPoint(getAngle(radiiPoints[0],radiiPoints[1]), OffLn2[0], startAngle,radiiPoints[0], Rp1),
|
||||
endP2b=findPoint(getAngle(radiiPoints[Lrp-1],radiiPoints[Lrp-2]), OffLn2[len(OffLn1)-1], endAngle,radiiPoints[Lrp-1], Rp2),
|
||||
|
||||
endP1aAngle = getAngle(radiiPoints[0],radiiPoints[1]),
|
||||
endP1a=findPoint(endP1aAngle, OffLn1[0], startAngle,radiiPoints[0], Rp1),
|
||||
|
||||
endP1bAngle = getAngle(radiiPoints[Lrp-1],radiiPoints[Lrp-2]),
|
||||
endP1b=findPoint(endP1bAngle, OffLn1[len(OffLn1)-1], endAngle,radiiPoints[Lrp-1], Rp2),
|
||||
|
||||
endP2aAngle = getAngle(radiiPoints[0],radiiPoints[1]),
|
||||
endP2a=findPoint(endP2aAngle, OffLn2[0], startAngle,radiiPoints[0], Rp1),
|
||||
|
||||
endP2bAngle = getAngle(radiiPoints[Lrp-1],radiiPoints[Lrp-2]),
|
||||
endP2b=findPoint(endP2bAngle, OffLn2[len(OffLn1)-1], endAngle,radiiPoints[Lrp-1], Rp2),
|
||||
|
||||
absEnda=getAngle(endP1a,endP2a),
|
||||
absEndb=getAngle(endP1b,endP2b),
|
||||
negRP1a=[cos(absEnda)*radiiPoints[0].z*10+endP1a.x, sin(absEnda)*radiiPoints[0].z*10+endP1a.y, 0.0],
|
||||
@@ -421,7 +451,7 @@ function CWorCCW(p)=
|
||||
(p[listWrap(i+0,Lp)].x-p[listWrap(i+1,Lp)].x)*(p[listWrap(i+0,Lp)].y+p[listWrap(i+1,Lp)].y)
|
||||
]
|
||||
)
|
||||
sign(sum(e));
|
||||
sign(polySum(e));
|
||||
|
||||
function CentreN2PointsArc(p1,p2,cen,mode=0,fn)=
|
||||
/* This function plots an arc from p1 to p2 with fn increments using the cen as the centre of the arc.
|
||||
@@ -432,22 +462,23 @@ function CentreN2PointsArc(p1,p2,cen,mode=0,fn)=
|
||||
mode==3, plotted counter clockwise
|
||||
*/
|
||||
let(
|
||||
CWorCCW=CWorCCW([cen,p1,p2]),//determine the direction of rotation
|
||||
isCWorCCW=CWorCCW([cen,p1,p2]),//determine the direction of rotation
|
||||
//determine the arc angle depending on the mode
|
||||
p1p2Angle=cosineRuleAngle(p2,cen,p1),
|
||||
arcAngle=
|
||||
mode==0?p1p2Angle:
|
||||
mode==1?p1p2Angle-360:
|
||||
mode==2&&CWorCCW==-1?p1p2Angle:
|
||||
mode==2&&CWorCCW== 1?p1p2Angle-360:
|
||||
mode==3&&CWorCCW== 1?p1p2Angle:
|
||||
mode==3&&CWorCCW==-1?p1p2Angle-360:
|
||||
cosineRuleAngle(p2,cen,p1)
|
||||
,
|
||||
mode==2&&isCWorCCW==-1?p1p2Angle:
|
||||
mode==2&&isCWorCCW== 1?p1p2Angle-360:
|
||||
mode==3&&isCWorCCW== 1?p1p2Angle:
|
||||
mode==3&&isCWorCCW==-1?p1p2Angle-360:
|
||||
cosineRuleAngle(p2,cen,p1),
|
||||
r=pointDist(p1,cen),//determine the radius
|
||||
p1Angle=getAngle(cen,p1) //angle of line 1
|
||||
)
|
||||
[for(i=[0:fn]) [cos(p1Angle+(arcAngle/fn)*i*CWorCCW)*r+cen[0],sin(p1Angle+(arcAngle/fn)*i*CWorCCW)*r+cen[1]]];
|
||||
[for(i=[0:fn])
|
||||
let(angleIncrement=(arcAngle/fn)*i*isCWorCCW)
|
||||
[cos(p1Angle+angleIncrement)*r+cen.x,sin(p1Angle+angleIncrement)*r+cen.y]];
|
||||
|
||||
function translateRadiiPoints(radiiPoints,tran=[0,0],rot=0)=
|
||||
[for(i=radiiPoints)
|
||||
@@ -539,7 +570,7 @@ function mirrorPoints(radiiPoints,rot=0,endAttenuation=[0,0])= //mirrors a list
|
||||
concat(radiiPoints,temp2);
|
||||
|
||||
function processRadiiPoints(rp)=
|
||||
[for(i=[0:len(rp)-1])
|
||||
[for(i=[0:len(rp)-1])
|
||||
processRadiiPoints2(rp,i)
|
||||
];
|
||||
|
||||
@@ -654,8 +685,8 @@ function cosineRuleAngle(p1,p2,p3)=
|
||||
)
|
||||
acos((sq(p23)+sq(p12)-sq(p13))/(2*p23*p12));
|
||||
|
||||
function sum(list, idx = 0, result = 0) =
|
||||
idx >= len(list) ? result : sum(list, idx + 1, result + list[idx]);
|
||||
function polySum(list, idx = 0, result = 0) =
|
||||
idx >= len(list) ? result : polySum(list, idx + 1, result + list[idx]);
|
||||
|
||||
function sq(x)=x*x;
|
||||
function getGradient(p1,p2)=(p2.y-p1.y)/(p2.x-p1.x);
|
||||
@@ -663,9 +694,9 @@ function getAngle(p1,p2)=p1==p2?0:invtan(p2[0]-p1[0],p2[1]-p1[1]);
|
||||
function getMidpoint(p1,p2)=[(p1[0]+p2[0])/2,(p1[1]+p2[1])/2]; //returns the midpoint of two points
|
||||
function pointDist(p1,p2)=sqrt(abs(sq(p1[0]-p2[0])+sq(p1[1]-p2[1]))); //returns the distance between two points
|
||||
function isColinear(p1,p2,p3)=getGradient(p1,p2)==getGradient(p2,p3)?1:0;//return 1 if 3 points are colinear
|
||||
module polyline(p) {
|
||||
module polyline(p, width=0.3) {
|
||||
for(i=[0:max(0,len(p)-1)]){
|
||||
line(p[i],p[listWrap(i+1,len(p) )]);
|
||||
color([i*1/len(p),1-i*1/len(p),0,0.5])line(p[i],p[listWrap(i+1,len(p) )],width);
|
||||
}
|
||||
} // polyline plotter
|
||||
module line(p1, p2 ,width=0.3) { // single line plotter
|
||||
|
@@ -1,6 +1,7 @@
|
||||
include <polyround.scad>
|
||||
|
||||
basicPolyRoundExample();
|
||||
// polyLineExample();
|
||||
// parametricPolyRoundExample();
|
||||
// experimentalParametricPolyRoundExample();
|
||||
// conflicResolutionExample();
|
||||
@@ -9,15 +10,27 @@ basicPolyRoundExample();
|
||||
// beamChainExample();
|
||||
// mirrorPointsExample();
|
||||
// radiusExtrudeExample();
|
||||
// radiusExtrudePolygon();
|
||||
// polyRoundExtrudeExample();
|
||||
|
||||
|
||||
// testing
|
||||
// testGeometries();
|
||||
|
||||
module basicPolyRoundExample(){
|
||||
// polyLine is a dev helper. Aim is to show the points of the polygon and their order before
|
||||
// you're ready to move on to polyRound and a polygon
|
||||
radiiPoints=[[-4,0,1],[5,3,1.5],[0,7,0.1],[8,7,10],[20,20,0.8],[10,0,10]];
|
||||
polygon(polyRound(radiiPoints,30));
|
||||
%translate([0,0,0.3])polygon(getpoints(radiiPoints));//transparent copy of the polgon without rounding
|
||||
}
|
||||
|
||||
module polyLineExample() {
|
||||
radiiPoints=[[-4,0,1],[5,3,1.5],[0,7,0.1],[8,7,10],[20,20,0.8],[10,0,10]];
|
||||
polyline(polyRound(radiiPoints,3), 0.05);
|
||||
translate([0,10,0])
|
||||
polyline(radiiPoints, 0.05);
|
||||
}
|
||||
|
||||
module parametricPolyRoundExample() {
|
||||
//Example of how a parametric part might be designed with this tool
|
||||
width=20; height=25;
|
||||
@@ -67,7 +80,7 @@ module experimentalParametricPolyRoundExample() {
|
||||
|
||||
module conflicResolutionExample(){
|
||||
//example of radii conflict handling and debuging feature
|
||||
function makeRadiiPoints(r1, r2)=[[0,0,0],[0,20,r1],[20,20,r1],[20,0,0]];
|
||||
function makeRadiiPoints(r1, r2)=[[0,0,0],[0,20,r1],[20,20,r2],[20,0,0]];
|
||||
|
||||
// the squre shape being 20 wide, two radii of 10 both fit into the shape (just)
|
||||
translate([-25,0,0])polygon(polyRound(makeRadiiPoints(10,10),50));
|
||||
@@ -79,7 +92,7 @@ module conflicResolutionExample(){
|
||||
translate([25,0,0])polygon(polyRound(makeRadiiPoints(10,40),50));
|
||||
|
||||
//mode 2 = no radii limiting
|
||||
translate([50,0,0])polygon(polyRound(makeRadiiPoints(15,20),50,mode=2));
|
||||
translate([50,0,0])polygon(polyRound(makeRadiiPoints(12,20),50,mode=2));
|
||||
}
|
||||
|
||||
module translateRadiiPointsExample() {
|
||||
@@ -113,8 +126,8 @@ module translateRadiiPointsExample() {
|
||||
|
||||
module 2dShellExample(){
|
||||
radiiPoints=[[-4,0,1],[5,3,1.5],[0,7,0.1],[8,7,10],[20,20,0.8],[10,0,10]];
|
||||
shell2d(-0.5)polygon(polyRound(radiiPoints,30));
|
||||
translate([0,-10,0])shell2d(-0.5){
|
||||
linear_extrude(1)shell2d(-0.5)polygon(polyRound(radiiPoints,30));
|
||||
translate([0,-10,0])linear_extrude(1)shell2d(-0.5){
|
||||
polygon(polyRound(radiiPoints,30));
|
||||
translate([8,8])gridpattern(memberW = 0.3, sqW = 1, iter = 17, r = 0.2);
|
||||
}
|
||||
@@ -124,43 +137,43 @@ module beamChainExample(){
|
||||
function beamPoints(r1,r2,rStart=0,rEnd=0)=[[0,0,rStart],[2,8,0],[5,4,r1],[15,10,r2],[17,2,rEnd]];
|
||||
|
||||
// chained lines by themselves
|
||||
translate(){
|
||||
translate([0,0,0]){
|
||||
radiiPoints=beamPoints(0,0);
|
||||
for(i=[0: len(radiiPoints)]){color("red")translate([radiiPoints[i].x,radiiPoints[i].y,0])cylinder(d=0.2, h=1);}
|
||||
polygon(polyRound(beamChain(radiiPoints,offset1=0.02, offset2=-0.02),20));
|
||||
for(i=[0: len(radiiPoints)-1]){color("red")translate([radiiPoints[i].x,radiiPoints[i].y,0])cylinder(d=0.2, h=1);}
|
||||
linear_extrude(1)polygon(polyRound(beamChain(radiiPoints,offset1=0.02, offset2=-0.02),20));
|
||||
}
|
||||
|
||||
|
||||
// Add some radii to the line transitions
|
||||
translate([0,-7,0]){
|
||||
radiiPoints=beamPoints(2,1);
|
||||
for(i=[0: len(ex3)]){color("red")translate([radiiPoints[i].x,radiiPoints[i].y,0])cylinder(d=0.2, h=1);}
|
||||
polygon(polyRound(beamChain(radiiPoints,offset1=0.02, offset2=-0.02),20));
|
||||
for(i=[0: len(radiiPoints)-1]){color("red")translate([radiiPoints[i].x,radiiPoints[i].y,0])cylinder(d=0.2, h=1);}
|
||||
linear_extrude(1)polygon(polyRound(beamChain(radiiPoints,offset1=0.02, offset2=-0.02),20));
|
||||
}
|
||||
|
||||
// Give make the lines beams with some thickness
|
||||
translate([0,-7*2,0]){
|
||||
radiiPoints=beamPoints(2,1);
|
||||
polygon(polyRound(beamChain(radiiPoints,offset1=0.5, offset2=-0.5),20));
|
||||
linear_extrude(1)polygon(polyRound(beamChain(radiiPoints,offset1=0.5, offset2=-0.5),20));
|
||||
}
|
||||
|
||||
// Add an angle to the start of the beam
|
||||
translate([0,-7*3,0]){
|
||||
radiiPoints=beamPoints(2,1);
|
||||
polygon(polyRound(beamChain(radiiPoints,offset1=0.5, offset2=-0.5, startAngle=45),20));
|
||||
linear_extrude(1)polygon(polyRound(beamChain(radiiPoints,offset1=0.5, offset2=-0.5, startAngle=45),20));
|
||||
}
|
||||
|
||||
// Put a negative radius at the start for transationing to a flat surface
|
||||
translate([0,-7*4,0]){
|
||||
radiiPoints=beamPoints(2,1,rStart=-0.7);
|
||||
polygon(polyRound(beamChain(radiiPoints,offset1=0.5, offset2=-0.5, startAngle=45),20));
|
||||
linear_extrude(1)polygon(polyRound(beamChain(radiiPoints,offset1=0.5, offset2=-0.5, startAngle=45),20));
|
||||
}
|
||||
|
||||
// Define more points for a polygon to be atteched to the end of the beam chain
|
||||
clipP=[[16,1.2,0],[16,0,0],[16.5,0,0],[16.5,1,0.2],[17.5,1,0.2],[17.5,0,0],[18,0,0],[18,1.2,0]];
|
||||
translate([-15,-7*5+3,0]){
|
||||
for(i=[0:len(clipP)-1]){color("red")translate([clipP[i].x,clipP[i].y,0])cylinder(d=0.2, h=1);}
|
||||
polygon(polyRound(clipP,20));
|
||||
linear_extrude(1)polygon(polyRound(clipP,20));
|
||||
}
|
||||
|
||||
// Attached to the end of the beam chain by dividing the beam paths in forward and return and
|
||||
@@ -170,7 +183,7 @@ module beamChainExample(){
|
||||
forwardPath=beamChain(radiiPoints,offset1=0.5,startAngle=-15,mode=2);
|
||||
returnPath=revList(beamChain(radiiPoints,offset1=-0.5,startAngle=-15,mode=2));
|
||||
entirePath=concat(forwardPath,clipP,returnPath);
|
||||
polygon(polyRound(entirePath,20));
|
||||
linear_extrude(1)polygon(polyRound(entirePath,20));
|
||||
}
|
||||
|
||||
// Add transitioning radii into the end polygong
|
||||
@@ -179,12 +192,13 @@ module beamChainExample(){
|
||||
forwardPath=beamChain(radiiPoints,offset1=0.5,startAngle=-15,mode=2);
|
||||
returnPath=revList(beamChain(radiiPoints,offset1=-0.5,startAngle=-15,mode=2));
|
||||
entirePath=concat(forwardPath,clipP,returnPath);
|
||||
polygon(polyRound(entirePath,20));
|
||||
linear_extrude(1)polygon(polyRound(entirePath,20));
|
||||
}
|
||||
|
||||
// Define multiple shells from the the one set of points
|
||||
translate([0,-7*9,0]){
|
||||
for(i=[0:2]){polygon(polyRound(beamChain(ex3,offset1=-1+i*0.4, offset2=-1+i*0.4+0.25),20));}
|
||||
radiiPoints=beamPoints(2,1,rEnd=3);
|
||||
for(i=[0:2]){linear_extrude(1)polygon(polyRound(beamChain(radiiPoints,offset1=-1+i*0.4, offset2=-1+i*0.4+0.25),20));}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,3 +229,41 @@ module gridpattern(memberW = 4, sqW = 12, iter = 5, r = 3){
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module testGeometries() {
|
||||
// Check these shapes preview (plus "thrown together") and render correctly with each PR
|
||||
points = [
|
||||
[0, 10, 5],
|
||||
[10, 0, 5],
|
||||
[0, -10, 5],
|
||||
[-10, 0, 5],
|
||||
];
|
||||
reversedPoints = [
|
||||
[-10, 0, 5],
|
||||
[0, -10, 5],
|
||||
[10, 0, 5],
|
||||
[0, 10, 5],
|
||||
];
|
||||
polyRoundExtrudeTestShape(points);
|
||||
translate([0,20,0])polyRoundExtrudeTestShape(reversedPoints);
|
||||
|
||||
// Bug report submitted by @lopisan in issue #16, similar to #11, geometry breaks with 90 degree angles
|
||||
didBreakWhen0=0;
|
||||
issue16pointsa=[[0, 0, 0], [0+didBreakWhen0, 10, 0], [10, 10+didBreakWhen0, 0]];
|
||||
translate([20,0,0])linear_extrude(1)polygon(polyRound( beamChain(issue16pointsa, offset1=1, offset2=-1), 30));
|
||||
|
||||
didBreakWhen0b=1e-6;
|
||||
issue16pointsb=[[0, 0, 0], [0+didBreakWhen0b, 10, 0], [10, 10+didBreakWhen0b, 0]];
|
||||
translate([20,15,0])linear_extrude(1)polygon(polyRound( beamChain(issue16pointsb, offset1=1, offset2=-1), 30));
|
||||
|
||||
}
|
||||
|
||||
module polyRoundExtrudeTestShape(points) {
|
||||
// make sure no faces are inverted
|
||||
difference() {
|
||||
translate([0, 0, -2.5]) polyRoundExtrude(points,r1=-1,r2=1);
|
||||
sphere(d=9);
|
||||
translate([0,0,7])sphere(d=9);
|
||||
}
|
||||
}
|
91
unionRoundMask-Doc.md
Normal file
91
unionRoundMask-Doc.md
Normal file
@@ -0,0 +1,91 @@
|
||||
## unionRoundMask / unionRound
|
||||
---
|
||||
### Union with round fillet at selected places. Created for Round-Anything by TLC123 (2021).
|
||||
A shortcut for faster fillet union is enabled when the operation constrained to convex operands.
|
||||
For most cases unionRoundMask / unionRound replaces MinkowskiRound.
|
||||
Combined with a system of mask selectors, unionRound becomes even more versetile.
|
||||
|
||||

|
||||
|
||||
## unionRoundMask
|
||||
---
|
||||
Union with round fillet at selected places.
|
||||
### module unionRoundMask(r=1, detail = 5 , q=70, epsilon = 1e-6, showMask = true , includeOperands = true)
|
||||
|
||||
Masks are a method to perform unionRound on selected only areas,
|
||||
and circumvents the previous limitation to common convex work area.
|
||||
Mask are essentially just common primitives that is used to mark out areas by intersection.
|
||||
|
||||
r:
|
||||
* approximate radius for fillet. Exact radius is dependant on crease angle.
|
||||
* detail: numbers of fillet segments. 1 is essensially a chamfer/bevel.
|
||||
* Set low for faster preview. ( $preview?3:10 )
|
||||
|
||||
q:
|
||||
* determine how detailed clad operations are.
|
||||
* Set low for faster preview. ( $preview?30:70 )
|
||||
|
||||
epsilon:
|
||||
* For debugging, leave as is.
|
||||
|
||||
showMask:
|
||||
* For debugging, try it.
|
||||
|
||||
includeOperands:
|
||||
* For debugging, render only fillet when false.
|
||||
|
||||
### usage:
|
||||
````
|
||||
unionRoundMask( r = 1 , detail = $preview ? 3 : 10 , q = $preview ? 30 : 70 )
|
||||
{
|
||||
yourObject1();
|
||||
yourObject2();
|
||||
yourMask1();
|
||||
yourMask2();
|
||||
yourMask3();
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
}
|
||||
````
|
||||
|
||||
---
|
||||
## unionRound
|
||||
---
|
||||
### module unionRound(r=1, detail = 5 , q=70, epsilon = 1e-6 , includeOperands = true )
|
||||
|
||||
Module unionRound is the underlying work module of unionRoundMask.
|
||||
It can be used by it self, in some cases faster but more raw.
|
||||
|
||||
### usage:
|
||||
````
|
||||
unionRoundMask( r = 1 , detail = $preview ? 3 : 10 , q= $preview ? 30 : 70 )
|
||||
{
|
||||
yourObject1();
|
||||
yourObject2();
|
||||
}
|
||||
````
|
||||
|
||||
---
|
||||
## intersectionRound
|
||||
---
|
||||
module intersectionRound(r, q=70, epsilon = 1e-6,showOperands = true)
|
||||
prototype module
|
||||
Undocumented for now.
|
||||
|
||||
---
|
||||
## helpers
|
||||
---
|
||||
````
|
||||
module clad(r,q=70) // speed is limited to convex operand.
|
||||
module shell(r,q=70) // not in use.
|
||||
module inset(r,q=20) // speed is limited to convex operand.
|
||||
````
|
||||
---
|
||||
## Citation
|
||||
---
|
||||
### roundUnionMask Includes code based on examples from:
|
||||
Kogan, Jonathan (2017)
|
||||
"A New Computationally Efficient Method for Spacing n Points on a Sphere,"
|
||||
Rose-Hulman Undergraduate Mathematics Journal: Vol. 18 : Iss. 2 , Article 5.
|
||||
Available at: [https://scholar.rose-hulman.edu/rhumj/vol18/iss2/5]
|
179
unionRoundMask.scad
Normal file
179
unionRoundMask.scad
Normal file
@@ -0,0 +1,179 @@
|
||||
////////////////////////////////////////////////////////
|
||||
/*
|
||||
unionRound() 1.0 Module by Torleif Ceder - TLC123 late summer 2021
|
||||
Pretty fast Union with radius, But limited to a subset of cases
|
||||
Usage
|
||||
unionRound( radius , detail )
|
||||
{
|
||||
YourObject1();
|
||||
YourObject2();
|
||||
}
|
||||
unionRoundMask (r, detail , epsilon ,showMask )
|
||||
{
|
||||
YourObject1();
|
||||
YourObject2();
|
||||
YourMask();
|
||||
YourMask();
|
||||
|
||||
// ...
|
||||
// ...
|
||||
// ...
|
||||
|
||||
}
|
||||
limitations:
|
||||
0. Only really fast when boolean operands are convex,
|
||||
Minkowski is fast in that case.
|
||||
1. Boolean operands may be concave but can only touch
|
||||
in a single convex area
|
||||
2. Radius is of elliptic type and is only approximate r
|
||||
were operand intersect at perpendicular angle.
|
||||
*/
|
||||
////////////////////////////////////////////////////////
|
||||
// Demo code
|
||||
demo= false;
|
||||
if (demo)
|
||||
unionRoundMask( r=1.5 , detail= 5 , q=70, includeOperands = true) {
|
||||
cube([10,10,2],true);
|
||||
rotate([20,-10,0])cylinder(5,1,1,$fn=12);
|
||||
translate([0,0,1.5])cube([1.5,10,3],center=true); //mask
|
||||
rotate(90)
|
||||
translate([0,0,1.5])cube([3,10,3],center=true); //mask
|
||||
}
|
||||
|
||||
// end of demo code
|
||||
//
|
||||
module unionRoundMask(r=1, detail = 5,q=70, epsilon = 1e-6, showMask = false, includeOperands = true) {
|
||||
//automask if none
|
||||
if($children <=2){
|
||||
unionRoundMask(r,detail,q,epsilon,showMask, includeOperands)
|
||||
{
|
||||
children(0);
|
||||
children(1);
|
||||
clad(max(r),q) intersection(){
|
||||
children(0);
|
||||
children(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
union() {
|
||||
if(includeOperands){
|
||||
children(0);
|
||||
children(1);
|
||||
}
|
||||
if (showMask && $children > 2) %
|
||||
for (i = [2: max(2, $children - 1)]) children(i);
|
||||
|
||||
if ($children > 2)
|
||||
for (i = [2: max(2, $children - 1)]) {
|
||||
intersection() {
|
||||
children(i);
|
||||
|
||||
unionRound(r, detail,q, epsilon,includeOperands) {
|
||||
intersection() {
|
||||
children(0);
|
||||
children(i); // mask
|
||||
}
|
||||
intersection() {
|
||||
children(1);
|
||||
children(i); // mask
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module unionRound(r=1, detail = 5,q=70, epsilon = 1e-6, includeOperands=true) {
|
||||
if(includeOperands){
|
||||
children(0);
|
||||
children(1);
|
||||
}
|
||||
step = 90 / detail;
|
||||
rx=is_list(r)?r[1]:r;
|
||||
ry=is_list(r)?r[0]:r;
|
||||
union()for (i = [0: detail-1]) {
|
||||
{
|
||||
x = rx - sin(i * step ) * rx;
|
||||
y = ry - cos(i * step ) * ry;
|
||||
xi = rx - sin((i * step + step) ) * rx;
|
||||
yi = ry - cos((i * step + step) ) * ry;
|
||||
// color(rands(0, 1, 3, i))
|
||||
hull() {
|
||||
intersection() {
|
||||
// shell(epsilon)
|
||||
clad(x,q) children(0);
|
||||
// shell(epsilon)
|
||||
clad(y,q) children(1);
|
||||
}
|
||||
intersection() {
|
||||
// shell(epsilon)
|
||||
clad(xi,q) children(0);
|
||||
// shell(epsilon)
|
||||
clad(yi,q) children(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// prototype module slow maybe on concave feature
|
||||
module intersectionRound(r, q=70, epsilon = 1e-6,showOperands = true) {
|
||||
%if (showOperands){children(0);
|
||||
children(1);}
|
||||
|
||||
clad(r,q) inset(r,q)
|
||||
hull()intersection() {
|
||||
children(0);
|
||||
children(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// unionRound helper expand by r
|
||||
module clad(r,q=70) {
|
||||
minkowski() {
|
||||
children();
|
||||
// icosphere(r,2);
|
||||
isosphere(r,q);
|
||||
}
|
||||
}
|
||||
// unionRound helper
|
||||
module shell(r,q=70) {
|
||||
difference() {
|
||||
clad(r,q) children();
|
||||
children();
|
||||
}
|
||||
}
|
||||
|
||||
// inset 3d "negative offset", optimally on convex hull
|
||||
// else jagged inner corners by q quality factor
|
||||
module inset(r,q=20){
|
||||
a= generatepoints(q)*r;
|
||||
//#children();
|
||||
intersection_for(t=a){
|
||||
translate(t ) children();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// The following is a sphere with some equidistant properties.
|
||||
// Not strictly necessary
|
||||
|
||||
Kogan, Jonathan (2017) "A New Computationally Efficient Method for Spacing n Points on a Sphere," Rose-Hulman Undergraduate Mathematics Journal: Vol. 18 : Iss. 2 , Article 5.
|
||||
Available at: https://scholar.rose-hulman.edu/rhumj/vol18/iss2/5 */
|
||||
|
||||
function sphericalcoordinate(x,y)= [cos(x )*cos(y ), sin(x )*cos(y ), sin(y )];
|
||||
function NX(n=70,x)=
|
||||
let(toDeg=57.2958,PI=acos(-1)/toDeg,
|
||||
start=(-1.+1./(n-1.)),increment=(2.-2./(n-1.))/(n-1.) )
|
||||
[ for (j= [0:n-1])let (s=start+j*increment )
|
||||
sphericalcoordinate( s*x*toDeg, PI/2.* sign(s)*(1.-sqrt(1.-abs(s)))*toDeg)];
|
||||
function generatepoints(n=70)= NX(n,0.1+1.2*n);
|
||||
module isosphere(r,q=70){
|
||||
a= generatepoints(q);
|
||||
scale(r)hull()polyhedron(a,[[for(i=[0:len(a)-1])i]]);
|
||||
}
|
Reference in New Issue
Block a user