1
0
mirror of https://github.com/Irev-Dev/Round-Anything.git synced 2025-09-30 17:08:59 +02:00

24 Commits
1.0.0 ... 1.0.3

Author SHA1 Message Date
Kurt Hutten
a6999a7202 Issue-16 Fix 90 degree bug in find findPoint
Actually very similar to issue-11, but I just didn't solve it 100%
2020-11-02 18:12:17 +11:00
Kurt Hutten
a85e6ffd48 Merge pull request #15 from Irev-Dev/irevdev/add-test-geometries
Add test geometries
2020-10-06 06:23:22 +11:00
Kurt Hutten
5a7b6db0ec Add test geometries
After pr #10, it makes sense to have some test shapes beyond the
examples to make sure there aren't regressions in the library,
Hopefully we'll add to this with time.
2020-10-06 06:21:28 +11:00
Kurt Hutten
6b16407430 Merge pull request #14 from Irev-Dev/irevdev/keep-polyround-extrude-height-consistent
Keep polyRound extrude height consistent
2020-10-06 05:41:33 +11:00
Kurt Hutten
9613a81f15 Keep polyRound extrude height consistent
when r1 changed between a positive and negative radius the height
of the extrude would change
2020-10-06 05:39:58 +11:00
Kurt Hutten
e6d67b6304 Merge pull request #10 from nickcoutsos/master
Invert flipped faces for polyRoundExtrude
2020-10-06 05:33:31 +11:00
Nick Coutsos
8d5b6a180b Normalize order of radiiPoints in polyRoundExtrude call 2020-10-05 12:48:31 -04:00
Kurt Hutten
0697444270 Merge pull request #13 from Irev-Dev/irevdev-fix-find-point-to-deal-with-90-deg-angles
Fix findPoint to deal with 90 degree angles
2020-10-05 20:45:11 +11:00
Kurt Hutten
764b3b7a73 Fix findPoint to deal with 90 degree angles
because tan(90) results in inf, some conditions were needed for these
cases
2020-10-05 20:41:30 +11:00
Nick Coutsos
a3934972b5 Invert flipped faces 2020-10-03 22:52:43 -04:00
Kurt Hutten
cb9e7f7b30 Merge pull request #9 from Irev-Dev/update-readme-to-include-video
update readme to include video
2020-08-24 17:55:21 +10:00
Kurt Hutten
1f15acb04b update readme to include video 2020-08-24 17:54:47 +10:00
Kurt Hutten
ddbb97b5ee Merge pull request #8 from Irev-Dev/remove-warnings-and-tweak-examples
Resolve warning messages and tweak examples
2020-08-17 05:46:42 +10:00
Kurt Hutten
40a14892f2 Resolve warning messages and tweak examples 2020-08-17 05:45:47 +10:00
Kurt Hutten
bf97548f88 Merge pull request #7 from Irev-Dev/update-polyRoundExtrude-api-a-little
Change polyRoundExtrude h to length in the api for consistency
2020-08-16 08:36:09 +10:00
Kurt Hutten
9b235f236b Change polyRoundExtrude h to length in the api for consistency 2020-08-16 08:35:03 +10:00
Kurt Hutten
ad61abc74a Fix readme typos 2020-08-10 13:19:41 +10:00
Kurt Hutten
aacf657b62 Read me tweak 2020-08-09 21:02:08 +10:00
Kurt Hutten
1d124289d4 Merge pull request #6 from Irev-Dev/update-readme
Update readme
2020-08-09 21:00:34 +10:00
Kurt Hutten
52afd869d0 Update readme 2020-08-09 20:59:32 +10:00
Kurt Hutten
3f9d124bb7 Merge pull request #5 from Irev-Dev/add-docs-for-polyRoundExtrude
Add docs and examples for ployRoundExtrude
2020-08-09 20:45:29 +10:00
Kurt Hutten
2c71de2b5e Add docs and examples for ployRoundExtrude 2020-08-09 20:44:44 +10:00
Kurt Hutten
e364960bea Merge pull request #4 from Irev-Dev/attempts-to-integrate-poly-round-into-curev-polyhedron
Add basis of extrude polygon with rounded ends
2020-08-09 14:44:41 +10:00
Kurt Hutten
6ee436a6b2 Add basis of extrude polygon with rounded ends
needs clean up work though
2020-08-09 14:43:52 +10:00
3 changed files with 304 additions and 64 deletions

View File

@@ -1,34 +1,29 @@
# Round-Anything
### minkowskiRound();
Is an incredibly powerful module that will allow you to fillet any of your OpenSCAD modules retrospectively while keeping the original dimensions. You don't need design your part again, or start using rounded cube modules etc, just throw minkowskiRound() out the front of it and your good to go. Also I hope the example in the first picture demonstrates that besides convenience of not having to add each fillet yourself, it will also fillet some areas (internal corners in particular) that are near impossible to fillet with other methods in SCAD.
Round-Anything is primarily a set of OpenSCAD utilities that help with rounding parts, but it also embodies a robust approach to developing OpenSCAD parts. The heart of the library a list of polygon points, with a 3rd radius parameter at each point. That is a series of [x, y, radius] points.
Biggest downside is that it is very computationally intensive, you will have to keep the $fn low (I would recommend 10-15 as a starting point) unless you are willing to wait a long time (12 hours plus). The modules have been made with an enable variable so that you can disable the module and keep designing and only add the fillets when you are ready to output your final model.
There is also a minkowskiInsideRound() and minkowskiOutsideRound() which takes less time to render if you only need inside or outside radii
<img src="https://cdn.sanity.io/images/2hqqc7om/production/5d73db6dfd44ab2606d5e3ff5d993361eba61c5e-1371x1567.png?w=500&h=571&fit=crop" width="100%" align="left">
### round2d();
Allows you to round any 2d object in openscad
## The Why
### polyRound();
is used the same way that polygon(); is used, however along with a list of coordinates, a list of radiuses should also be supplied and the corners will be rounded with these radiuses.
This is can be incredible useful if you try and design parts using extruded 2d polygons instead of with primatives since radiuses are generally hard to implement in OpenSCAD (internal radiuses in particular). see examples below.
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.
I would love if people sent me examples that I can upload along with the ones I have here.
## Documentation
[thingiverse page here](https://www.thingiverse.com/thing:2419664)
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>
### Examples
##### minkowsikRound();
<img src="https://github.com/Irev-Dev/Round-Anything/blob/master/images/mainminkowski.png" width="100%" align="left">
##### minkowsikInsideRound(); & minkowsikOutsideRound();
<img src="https://github.com/Irev-Dev/Round-Anything/blob/master/images/InOutminkowski.png" width="100%" align="left">
[Written overview](https://kurthutten.com/blog/round-anything-a-pragmatic-approach-to-openscad-design/).
##### round2d();
<img src="https://github.com/Irev-Dev/Round-Anything/blob/master/images/round2d.png" width="100%" align="left">
[Full documentation of the API is here](https://kurthutten.com/blog/round-anything-api/).
##### polyRound();
<img src="https://github.com/Irev-Dev/Round-Anything/blob/master/images/example1.png" width="100%" align="left">
<img src="https://github.com/Irev-Dev/Round-Anything/blob/master/images/PolyRoundexample3fn.png" width="100%" align="left">
<img src="https://github.com/Irev-Dev/Round-Anything/blob/master/images/example2.png" width="100%" align="left">
## 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.
<img src="https://cdn.thingiverse.com/assets/ea/fb/83/89/57/featured_preview_camera_mount.png" width="100%" align="left">
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">

View File

@@ -6,7 +6,174 @@
// License: MIT
function addZcoord(points,displacement)=[for(i=[0:len(points)-1])[points[i].x,points[i].y, displacement]];
function translate3Dcoords(points,tran=[0,0,0],mult=[1,1,1])=[for(i=[0:len(points)-1])[
(points[i].x*mult.x)+tran.x,
(points[i].y*mult.y)+tran.y,
(points[i].z*mult.z)+tran.z
]];
function offsetPolygonPoints(points, offset=0)=
// Work sthe same as the offset does, except for the fact that instead of a 2d shape
// It works directly on polygon points
// It returns the same number of points just offset into or, away from the original shape.
// points= a series of x,y points[[x1,y1],[x2,y2],...]
// offset= amount to offset by, negative numbers go inwards into the shape, positive numbers go out
// return= a series of x,y points[[x1,y1],[x2,y2],...]
let(
isCWorCCW=sign(offset)*CWorCCW(points)*-1,
lp=len(points)
)
[for(i=[0:lp-1]) parallelFollow([
points[listWrap(i-1,lp)],
points[i],
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
// r= radius of curve that will be put on the end of the extrusion
// fn= amount of subdivisions
// minR= if one of the points in radiiPoints is less than r, it's likely to converge and form a sharp edge,
// the min radius on these converged edges can be controled with minR, though because of legacy reasons it can't be 0, but can be a very small number.
// return= array of [polyhedronPoints, Polyhedronfaces, theLength of a singe layer in the curve]
let(
lp=len(radiiPoints),
radii=[for(i=[0:lp-1])radiiPoints[i].z],
isCWorCCWOverall=CWorCCW(radiiPoints),
dir=sign(r),
absR=abs(r),
fractionOffLp=1-1/fn,
allPoints=[for(fraction=[0:1/fn:1])
let(
iterationOffset=dir*sqrt(sq(absR)-sq(fraction*absR))-dir*absR,
theOffsetPoints=offsetPolygonPoints(radiiPoints,iterationOffset),
polyRoundOffsetPoints=[for(i=[0:lp-1])
let(
pointsAboutCurrent=[
theOffsetPoints[listWrap(i-1,lp)],
theOffsetPoints[i],
theOffsetPoints[listWrap(i+1,lp)]
],
isCWorCCWLocal=CWorCCW(pointsAboutCurrent),
isInternalRadius=(isCWorCCWLocal*isCWorCCWOverall)==-1,
// the radius names are only true for positive r,
// when are r is negative increasingRadius is actually decreasing and vice-vs
// increasingRadiusWithPositiveR is just to verbose of a variable name for my liking
increasingRadius=max(radii[i]-iterationOffset, minR),
decreasingRadius=max(radii[i]+iterationOffset, minR)
)
[theOffsetPoints[i].x, theOffsetPoints[i].y, isInternalRadius? increasingRadius: decreasingRadius]
],
pointsForThisLayer=polyRound(polyRoundOffsetPoints,fn)
)
addZcoord(pointsForThisLayer,fraction*absR)
],
polyhedronPoints=flatternArray(allPoints),
allLp=len(allPoints),
layerLength=len(allPoints[0]),
loopToSecondLastLayer=allLp-2,
sideFaces=[for(layerIndex=[0:loopToSecondLastLayer])let(
currentLayeroffset=layerIndex*layerLength,
nextLayeroffset=(layerIndex+1)*layerLength,
layerFaces=[for(subLayerIndex=[0:layerLength-1])
[
currentLayeroffset+subLayerIndex, currentLayeroffset + listWrap(subLayerIndex+1,layerLength), nextLayeroffset+listWrap(subLayerIndex+1,layerLength), nextLayeroffset+subLayerIndex]
]
)layerFaces],
polyhedronFaces=flatternArray(sideFaces)
)
[polyhedronPoints, polyhedronFaces, layerLength];
function flatternRecursion(array, init=[], currentIndex)=
// 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
// init= the array used to cancat with the next call, only for when the function calls itself
// currentIndex= so the function can keep track of how far it's progressed through the array, only for when it's calling itself
// returns= flatterned array, by one level of nesting
let(
shouldKickOffRecursion=currentIndex==undef?1:0,
isLastIndex=currentIndex+1==len(array)?1:0,
flatArray=shouldKickOffRecursion?flatternRecursion(array,[],0):
isLastIndex?concat(init,array[currentIndex]):
flatternRecursion(array,concat(init,array[currentIndex]),currentIndex+1)
)
flatArray;
function flatternArray(array)=
// public version of flatternRecursion, has simplified params to avoid confusion
// array= array to be flatterned
// return= array that been flatterend by one level of nesting
flatternRecursion(array);
function offsetAllFacesBy(array,offset)=[
// polyhedron faces are simply a list of indices to points, if your concat points together than you probably need to offset
// your faces array to points to the right place in the new list
// array= array of point indicies
// offset= number to offset all indecies by
// return= array of point indices (i.e. faces) with offset applied
for(faceIndex=[0:len(array)-1])[
for(pointIndex=[0:len(array[faceIndex])-1])array[faceIndex][pointIndex]+offset
]
];
function extrudePolygonWithRadius(radiiPoints,h=5,r1=1,r2=1,fn=4)=
// this basically calls makeCurvedPartOfPolyHedron twice to get the curved section of the final polyhedron
// and then goes about assmbling them, as the side faces and the top and bottom face caps are missing
// radiiPoints= series of [x,y,r] points,
// h= height of the extrude (total including radius sections)
// r1,r2= define the radius at the top and bottom of the extrud respectively, negative number flange out the extrude
// fn= number of subdivisions
// returns= [polyhedronPoints, polyhedronFaces]
let(
// top is the top curved part of the extrude
top=makeCurvedPartOfPolyHedron(radiiPoints,r1,fn),
topRadiusPoints=translate3Dcoords(top[0],[0,0,h-abs(r1)]),
singeLayerLength=top[2],
topRadiusFaces=top[1],
radiusPointsLength=len(topRadiusPoints), // is the same length as bottomRadiusPoints
// bottom is the bottom curved part of the extrude
bottom=makeCurvedPartOfPolyHedron(radiiPoints,r2,fn),
// Z axis needs to be multiplied by -1 to flip it so the radius is going in the right direction [1,1,-1]
bottomRadiusPoints=translate3Dcoords(bottom[0],[0,0,abs(r2)],[1,1,-1]),
// becaues the points will be all concatenated into the same array, and the bottom points come second, than
// the original indices the faces are points towards are wrong and need to have an offset applied to them
bottomRadiusFaces=offsetAllFacesBy(bottom[1],radiusPointsLength),
// all of the side panel of the extrusion, connecting points from the inner layers of each
// of the curved sections
sideFaces=[for(i=[0:singeLayerLength-1])[
i,
listWrap(i+1,singeLayerLength),
radiusPointsLength + listWrap(i+1,singeLayerLength),
radiusPointsLength + i
]],
// both of these caps are simple every point from the last layer of the radius points
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,invertFaces(bottomRadiusFaces),invertFaces(sideFaces),[topCapFace],invertFaces([bottomCapFace]))
)
[
finalPolyhedronPoints,
finalPolyhedronFaces
];
module polyRoundExtrude(radiiPoints,length=5,r1=1,r2=1,fn=10,convexity=10) {
orderedRadiiPoints = CWorCCW(radiiPoints) == 1
? reverseList(radiiPoints)
: radiiPoints;
polyhedronPointsNFaces=extrudePolygonWithRadius(orderedRadiiPoints,length,r1,r2,fn);
polyhedron(points=polyhedronPointsNFaces[0], faces=polyhedronPointsNFaces[1], convexity=convexity);
}
// testingInternals();
module testingInternals(){
//example of rounding random points, this has no current use but is a good demonstration
@@ -169,14 +336,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];
@@ -216,13 +391,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],
@@ -274,22 +459,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)
@@ -351,17 +537,17 @@ module extrudeWithRadius(length,r1=0,r2=0,fn=30){
children();
}
}
for(i=[0:1/fn:1]){
translate([0,0,i*r1]){
linear_extrude(r1/fn){
offset(n1*sqrt(sq(r1)-sq(r1-i*r1))-n1*r1){
for(i=[0:fn-1]){
translate([0,0,i/fn*r1]){
linear_extrude(r1/fn+0.01){
offset(n1*sqrt(sq(r1)-sq(r1-i/fn*r1))-n1*r1){
children();
}
}
}
translate([0,0,length-r2+i*r2]){
linear_extrude(r2/fn){
offset(n2*sqrt(sq(r2)-sq(i*r2))-n2*r2){
translate([0,0,length-r2+i/fn*r2]){
linear_extrude(r2/fn+0.01){
offset(n2*sqrt(sq(r2)-sq(i/fn*r2))-n2*r2){
children();
}
}
@@ -381,7 +567,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)
];
@@ -505,9 +691,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

View File

@@ -1,6 +1,7 @@
include <polyround.scad>
basicPolyRoundExample();
// polyLineExample();
// parametricPolyRoundExample();
// experimentalParametricPolyRoundExample();
// conflicResolutionExample();
@@ -9,13 +10,27 @@ basicPolyRoundExample();
// beamChainExample();
// mirrorPointsExample();
// radiusExtrudeExample();
// 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;
@@ -65,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));
@@ -77,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() {
@@ -111,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);
}
@@ -122,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
@@ -168,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
@@ -177,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));}
}
}
@@ -200,6 +216,11 @@ module radiusExtrudeExample(){
#translate([7,4,3])extrudeWithRadius(3,-0.5,0.95,50)circle(1,$fn=30);
}
module polyRoundExtrudeExample(){
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=8);
}
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]);
@@ -208,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);
}
}