From dd02e9751dad644b383d9e425c62db1f1c3b6946 Mon Sep 17 00:00:00 2001 From: Nathan Hellweg Date: Tue, 30 Jan 2018 09:50:53 -0800 Subject: [PATCH 1/7] Added a heavy roundedcube 'primitive' and added a face triangulation function to subdivision.scad --- roundedcube.scad | 149 +++++++++++++++++++++++++++++++++++++++++++++++ subdivision.scad | 110 ++++++++++++++++++++++++++++++++++ 2 files changed, 259 insertions(+) create mode 100644 roundedcube.scad diff --git a/roundedcube.scad b/roundedcube.scad new file mode 100644 index 0000000..29a5b88 --- /dev/null +++ b/roundedcube.scad @@ -0,0 +1,149 @@ +use + +/* Rounded cube using the cube/octahedron duality. */ + +function rounded_cube(size, r=0, center=false, fn=12)= + (!is_array(size))? + rounded_cube(size=[size,size,size],r=r,center=center,fn=fn) + :(r>=min(size[0],size[1],size[2])/2)? + rounded_cube(size=size,r=min(size[0],size[1],size[2])/2-.0001,center=center,fn=fn) + :(r<=0)? + cube(size,center=center) + : + let( + steps=(fn>0)?ceil(fn/4):1, + sx=size[0]/2-r, + sy=size[1]/2-r, + sz=size[2]/2-r, + da=90/steps, + count=4*(steps+1)*(steps+2)-1, + rcube=[ + flatten(concat( + [for (i=[0:steps]) + let( + z=r*(-cos(da*i))-sz, + l=r*sin(da*i), + dp=(i>0)?(90/i):0 + ) + concat( + [for(j=[0:i]) [sx+l*cos(dp*j),sy+l*sin(dp*j),z]], + [for(j=[0:i]) [-sx-l*sin(dp*j),sy+l*cos(dp*j),z]], + [for(j=[0:i]) [-sx-l*cos(dp*j),-sy-l*sin(dp*j),z]], + [for(j=[0:i]) [sx+l*sin(dp*j),-sy-l*cos(dp*j),z]] + ) + ], + [for (i=[steps:-1:0]) + let( + z=sz+r*cos(da*i), + l=r*sin(da*i), + dp=(i>0)?90/i:0 + ) + concat( + [for(j=[0:i]) [sx+l*cos(dp*j),sy+l*sin(dp*j),z]], + [for(j=[0:i]) [-sx-l*sin(dp*j),sy+l*cos(dp*j),z]], + [for(j=[0:i]) [-sx-l*cos(dp*j),-sy-l*sin(dp*j),z]], + [for(j=[0:i]) [sx+l*sin(dp*j),-sy-l*cos(dp*j),z]] + ) + ] + )), +//Each side on the i'th row has i+1 points +//The rows start with 0,4,8,12 ... 2*i*(i+1) +//Each side on the ith row has i+1 points + concat( + [[0,1,2,3]], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) + [ + laststart+lpps*side, + laststart+(lpps*side+lppl-1)%lppl, + start+(pps*side+ppl-1)%ppl, + start+pps*side + ] + ], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-1]) + [ + laststart+lpps*side+j, + start+pps*side+j, + start+pps*side+1+j + ] + ], + (steps<2)?[]: [for(i=[2:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-2]) + [ + laststart+lpps*side+j, + start+pps*side+j+1, + laststart+lpps*side+j+1 + ] + ], +//These faces fuse the top & bottom +//The steps'th row starts with 2*steps*(steps+1) +//The (steps+1)'th row starts with 2*steps*(steps+1)+4*steps + [for(side=[0:3]) let(start=2*steps*(steps+1)+4*(steps+1), + laststart=2*steps*(steps+1), + ppl=4*(steps+1),lppl=4*(steps+1), + pps=(steps+1),lpps=(steps+1) + ) for(j=[0:steps]) + + [ + laststart+lpps*side+j, + laststart+(lpps*side+lppl-1+j)%lppl, + start+(pps*side+ppl-1+j)%ppl, + start+pps*side+j + ] + ], +//And the top is just the bottom wound in reverse. + [[count-0,count-1,count-2,count-3]], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) + [ + count-(laststart+lpps*side), + count-(laststart+(lpps*side+lppl-1)%lppl), + count-(start+(pps*side+ppl-1)%ppl), + count-(start+pps*side) + ] + ], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-1]) + [ + count-(laststart+lpps*side+j), + count-(start+pps*side+j), + count-(start+pps*side+1+j) + ] + ], + (steps<2)?[]: [for(i=[2:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-2]) + [ + count-(laststart+lpps*side+j), + count-(start+pps*side+j+1), + count-(laststart+lpps*side+j+1) + ] + ] + ) + ] + ) + center?rcube:translate(size/2,rcube) +; + +rcube=(rounded_cube([1,2,3],1/3,fn=24,center=false)); +poly3d(rcube); + + diff --git a/subdivision.scad b/subdivision.scad index 27f9f43..28b0b8b 100644 --- a/subdivision.scad +++ b/subdivision.scad @@ -28,3 +28,113 @@ function subdivide_faces(n=1, poly) = ]) ) n > 1 ? subdivide_faces(n-1, [allpoints, faces]) : n > 0 ? [allpoints,faces] : poly; + +//Utility function for splitting circular vectors. +function range (list,start,end)= + (end i ? v[i] + vsum(v, i+1) : [0,0,0]; + +//Ineffictient (Order N^2) naive face triangulation function that works +//by ear clipping: +//Finds a convex vertex (order N) +//Checks if the 'ear' with that vertex contains any points. +//If not, the ear can be clipped, otherwise there's a diagonal in the ear, + +function triangulate_poly3d(poly)= + [poly[0],triangulate_faces(poly[0],poly[1])] +; + +function triangulate_faces(points,faces)= + flatten([for(i=[0:len(faces)-1]) triangulate_face(points,faces[i])]) +; + +function triangulate_face(points,face)= + let(count=len(face)) + (3==count)? + [face] + : + let(wd=winding_direction(points,face),cv=convexvertex(wd,points,face), + pv=(count+cv-1)%count,nv=(cv+1)%count, + p0=points[face[pv]],p1=points[face[cv]],p2=points[face[nv]], + tests=[ + [cross(wd,p0-p2),cross(wd,p0-p2)*p0], + [cross(wd,p1-p0),cross(wd,p1-p0)*p1], + [cross(wd,p2-p1),cross(wd,p2-p1)*p2] + ], + eartest=pointinear(points,face,tests), + clipableear=(eartest[0]<0), + diagonalpoint=eartest[1] + ) + (clipableear)? //There is no point inside the ear. + flatten([ + [range(face,pv,nv)], + triangulate_face(points,range(face,nv,pv)) + ]) + : //If there is a point inside the ear, make a diagonal and clip along that. + flatten([ + triangulate_face(points,range(face,cv,diagonalpoint)), + triangulate_face(points,range(face,diagonalpoint,cv)) + ]) +; + + +function winding_direction(points,face)= + let(count=len(face)) + vsum([for(i=[0:count-1]) cross(points[face[(i+1)%count]]-points[face[(i)%count]],points[face[(i+2)%count]]-points[face[(i+1)%count]])],0) +; + +function convexvertex(wd,points,face,i=0)= + let(count=len(face)-1, + p0=points[face[i]],p1=points[face[(i+1)%count]],p2=points[face[(i+2)%count]] + ) + (len(face)>i)? + (cross(p1-p0,p2-p1)*wd>0)? + (i+1)%count + : + convexvertex(wd,points,face,i+1) + ://This should never happen since there is at least 1 convex vertex. + undef +; + +//The order of tests matters - This assumes Test 0 indicates which point is furthest in +//the ear - and that point will form a diagonal with the tip of the ear. + +function pointinear(points,face,tests,i=0)= + (iprev[0])? + [test,i] + : + prev + : + [checkpointinear(points[face[i]],tests),i] +; + +function checkpointinear (point,tests)= + let( + result=[ + (point*tests[0][0])-tests[0][1], + (point*tests[1][0])-tests[1][1], + (point*tests[2][0])-tests[2][1] + ] + ) + (result[0]>0 && result[1]>0 && result[2]>0)? + result[0] + : + -1 +; + + + + + + + From 53a743cb18f8ac1865dd418e7932414008c152a9 Mon Sep 17 00:00:00 2001 From: Nathan Hellweg Date: Tue, 30 Jan 2018 14:09:13 -0800 Subject: [PATCH 2/7] Polygon face triangulation --- roundedcube.scad | 149 ----------------------------------------------- 1 file changed, 149 deletions(-) delete mode 100644 roundedcube.scad diff --git a/roundedcube.scad b/roundedcube.scad deleted file mode 100644 index 29a5b88..0000000 --- a/roundedcube.scad +++ /dev/null @@ -1,149 +0,0 @@ -use - -/* Rounded cube using the cube/octahedron duality. */ - -function rounded_cube(size, r=0, center=false, fn=12)= - (!is_array(size))? - rounded_cube(size=[size,size,size],r=r,center=center,fn=fn) - :(r>=min(size[0],size[1],size[2])/2)? - rounded_cube(size=size,r=min(size[0],size[1],size[2])/2-.0001,center=center,fn=fn) - :(r<=0)? - cube(size,center=center) - : - let( - steps=(fn>0)?ceil(fn/4):1, - sx=size[0]/2-r, - sy=size[1]/2-r, - sz=size[2]/2-r, - da=90/steps, - count=4*(steps+1)*(steps+2)-1, - rcube=[ - flatten(concat( - [for (i=[0:steps]) - let( - z=r*(-cos(da*i))-sz, - l=r*sin(da*i), - dp=(i>0)?(90/i):0 - ) - concat( - [for(j=[0:i]) [sx+l*cos(dp*j),sy+l*sin(dp*j),z]], - [for(j=[0:i]) [-sx-l*sin(dp*j),sy+l*cos(dp*j),z]], - [for(j=[0:i]) [-sx-l*cos(dp*j),-sy-l*sin(dp*j),z]], - [for(j=[0:i]) [sx+l*sin(dp*j),-sy-l*cos(dp*j),z]] - ) - ], - [for (i=[steps:-1:0]) - let( - z=sz+r*cos(da*i), - l=r*sin(da*i), - dp=(i>0)?90/i:0 - ) - concat( - [for(j=[0:i]) [sx+l*cos(dp*j),sy+l*sin(dp*j),z]], - [for(j=[0:i]) [-sx-l*sin(dp*j),sy+l*cos(dp*j),z]], - [for(j=[0:i]) [-sx-l*cos(dp*j),-sy-l*sin(dp*j),z]], - [for(j=[0:i]) [sx+l*sin(dp*j),-sy-l*cos(dp*j),z]] - ) - ] - )), -//Each side on the i'th row has i+1 points -//The rows start with 0,4,8,12 ... 2*i*(i+1) -//Each side on the ith row has i+1 points - concat( - [[0,1,2,3]], - [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) - [ - laststart+lpps*side, - laststart+(lpps*side+lppl-1)%lppl, - start+(pps*side+ppl-1)%ppl, - start+pps*side - ] - ], - [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) for(j=[0:i-1]) - [ - laststart+lpps*side+j, - start+pps*side+j, - start+pps*side+1+j - ] - ], - (steps<2)?[]: [for(i=[2:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) for(j=[0:i-2]) - [ - laststart+lpps*side+j, - start+pps*side+j+1, - laststart+lpps*side+j+1 - ] - ], -//These faces fuse the top & bottom -//The steps'th row starts with 2*steps*(steps+1) -//The (steps+1)'th row starts with 2*steps*(steps+1)+4*steps - [for(side=[0:3]) let(start=2*steps*(steps+1)+4*(steps+1), - laststart=2*steps*(steps+1), - ppl=4*(steps+1),lppl=4*(steps+1), - pps=(steps+1),lpps=(steps+1) - ) for(j=[0:steps]) - - [ - laststart+lpps*side+j, - laststart+(lpps*side+lppl-1+j)%lppl, - start+(pps*side+ppl-1+j)%ppl, - start+pps*side+j - ] - ], -//And the top is just the bottom wound in reverse. - [[count-0,count-1,count-2,count-3]], - [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) - [ - count-(laststart+lpps*side), - count-(laststart+(lpps*side+lppl-1)%lppl), - count-(start+(pps*side+ppl-1)%ppl), - count-(start+pps*side) - ] - ], - [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) for(j=[0:i-1]) - [ - count-(laststart+lpps*side+j), - count-(start+pps*side+j), - count-(start+pps*side+1+j) - ] - ], - (steps<2)?[]: [for(i=[2:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) for(j=[0:i-2]) - [ - count-(laststart+lpps*side+j), - count-(start+pps*side+j+1), - count-(laststart+lpps*side+j+1) - ] - ] - ) - ] - ) - center?rcube:translate(size/2,rcube) -; - -rcube=(rounded_cube([1,2,3],1/3,fn=24,center=false)); -poly3d(rcube); - - From 1ea16d0378c9cfd36bec2c11b9600fad75791d50 Mon Sep 17 00:00:00 2001 From: Nathan Hellweg Date: Tue, 30 Jan 2018 14:15:49 -0800 Subject: [PATCH 3/7] Add roundedcube.scad for rounded cube. --- roundedcube.scad | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 roundedcube.scad diff --git a/roundedcube.scad b/roundedcube.scad new file mode 100644 index 0000000..da0baea --- /dev/null +++ b/roundedcube.scad @@ -0,0 +1,148 @@ +use + +/* Rounded cube using the cube/octahedron duality. */ + +function rounded_cube(size, r=0, center=false, fn=12)= + (!is_array(size))? + rounded_cube(size=[size,size,size],r=r,center=center,fn=fn) + :(r>=min(size[0],size[1],size[2])/2)? + rounded_cube(size=size,r=min(size[0],size[1],size[2])/2-.0001,center=center,fn=fn) + :(r<=0)? + cube(size,center=center) + : + let( + steps=(fn>0)?ceil(fn/4):1, + sx=size[0]/2-r, + sy=size[1]/2-r, + sz=size[2]/2-r, + da=90/steps, + count=4*(steps+1)*(steps+2)-1, + rcube=[ + flatten(concat( + [for (i=[0:steps]) + let( + z=r*(-cos(da*i))-sz, + l=r*sin(da*i), + dp=(i>0)?(90/i):0 + ) + concat( + [for(j=[0:i]) [sx+l*cos(dp*j),sy+l*sin(dp*j),z]], + [for(j=[0:i]) [-sx-l*sin(dp*j),sy+l*cos(dp*j),z]], + [for(j=[0:i]) [-sx-l*cos(dp*j),-sy-l*sin(dp*j),z]], + [for(j=[0:i]) [sx+l*sin(dp*j),-sy-l*cos(dp*j),z]] + ) + ], + [for (i=[steps:-1:0]) + let( + z=sz+r*cos(da*i), + l=r*sin(da*i), + dp=(i>0)?90/i:0 + ) + concat( + [for(j=[0:i]) [sx+l*cos(dp*j),sy+l*sin(dp*j),z]], + [for(j=[0:i]) [-sx-l*sin(dp*j),sy+l*cos(dp*j),z]], + [for(j=[0:i]) [-sx-l*cos(dp*j),-sy-l*sin(dp*j),z]], + [for(j=[0:i]) [sx+l*sin(dp*j),-sy-l*cos(dp*j),z]] + ) + ] + )), +//Each side on the i'th row has i+1 points +//The rows start with 0,4,8,12 ... 2*i*(i+1) +//Each side on the ith row has i+1 points + concat( + [[0,1,2,3]], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) + [ + laststart+lpps*side, + laststart+(lpps*side+lppl-1)%lppl, + start+(pps*side+ppl-1)%ppl, + start+pps*side + ] + ], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-1]) + [ + laststart+lpps*side+j, + start+pps*side+j, + start+pps*side+1+j + ] + ], + (steps<2)?[]: [for(i=[2:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-2]) + [ + laststart+lpps*side+j, + start+pps*side+j+1, + laststart+lpps*side+j+1 + ] + ], +//These faces fuse the top & bottom +//The steps'th row starts with 2*steps*(steps+1) +//The (steps+1)'th row starts with 2*steps*(steps+1)+4*steps + [for(side=[0:3]) let(start=2*steps*(steps+1)+4*(steps+1), + laststart=2*steps*(steps+1), + ppl=4*(steps+1),lppl=4*(steps+1), + pps=(steps+1),lpps=(steps+1) + ) for(j=[0:steps]) + + [ + laststart+lpps*side+j, + laststart+(lpps*side+lppl-1+j)%lppl, + start+(pps*side+ppl-1+j)%ppl, + start+pps*side+j + ] + ], +//And the top is just the bottom wound in reverse. + [[count-0,count-1,count-2,count-3]], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) + [ + count-(laststart+lpps*side), + count-(laststart+(lpps*side+lppl-1)%lppl), + count-(start+(pps*side+ppl-1)%ppl), + count-(start+pps*side) + ] + ], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-1]) + [ + count-(laststart+lpps*side+j), + count-(start+pps*side+j), + count-(start+pps*side+1+j) + ] + ], + (steps<2)?[]: [for(i=[2:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-2]) + [ + count-(laststart+lpps*side+j), + count-(start+pps*side+j+1), + count-(laststart+lpps*side+j+1) + ] + ] + ) + ] + ) + center?rcube:translate(size/2,rcube) +; + +rcube=(rounded_cube([3,2,1],1/3,fn=24,center=false)); +poly3d(rcube); + From 92a32a46fef7df33f89cce950f5061752ec2e75e Mon Sep 17 00:00:00 2001 From: Nathan Hellweg Date: Tue, 30 Jan 2018 14:17:36 -0800 Subject: [PATCH 4/7] roundedcube out again --- roundedcube.scad | 148 ----------------------------------------------- 1 file changed, 148 deletions(-) delete mode 100644 roundedcube.scad diff --git a/roundedcube.scad b/roundedcube.scad deleted file mode 100644 index da0baea..0000000 --- a/roundedcube.scad +++ /dev/null @@ -1,148 +0,0 @@ -use - -/* Rounded cube using the cube/octahedron duality. */ - -function rounded_cube(size, r=0, center=false, fn=12)= - (!is_array(size))? - rounded_cube(size=[size,size,size],r=r,center=center,fn=fn) - :(r>=min(size[0],size[1],size[2])/2)? - rounded_cube(size=size,r=min(size[0],size[1],size[2])/2-.0001,center=center,fn=fn) - :(r<=0)? - cube(size,center=center) - : - let( - steps=(fn>0)?ceil(fn/4):1, - sx=size[0]/2-r, - sy=size[1]/2-r, - sz=size[2]/2-r, - da=90/steps, - count=4*(steps+1)*(steps+2)-1, - rcube=[ - flatten(concat( - [for (i=[0:steps]) - let( - z=r*(-cos(da*i))-sz, - l=r*sin(da*i), - dp=(i>0)?(90/i):0 - ) - concat( - [for(j=[0:i]) [sx+l*cos(dp*j),sy+l*sin(dp*j),z]], - [for(j=[0:i]) [-sx-l*sin(dp*j),sy+l*cos(dp*j),z]], - [for(j=[0:i]) [-sx-l*cos(dp*j),-sy-l*sin(dp*j),z]], - [for(j=[0:i]) [sx+l*sin(dp*j),-sy-l*cos(dp*j),z]] - ) - ], - [for (i=[steps:-1:0]) - let( - z=sz+r*cos(da*i), - l=r*sin(da*i), - dp=(i>0)?90/i:0 - ) - concat( - [for(j=[0:i]) [sx+l*cos(dp*j),sy+l*sin(dp*j),z]], - [for(j=[0:i]) [-sx-l*sin(dp*j),sy+l*cos(dp*j),z]], - [for(j=[0:i]) [-sx-l*cos(dp*j),-sy-l*sin(dp*j),z]], - [for(j=[0:i]) [sx+l*sin(dp*j),-sy-l*cos(dp*j),z]] - ) - ] - )), -//Each side on the i'th row has i+1 points -//The rows start with 0,4,8,12 ... 2*i*(i+1) -//Each side on the ith row has i+1 points - concat( - [[0,1,2,3]], - [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) - [ - laststart+lpps*side, - laststart+(lpps*side+lppl-1)%lppl, - start+(pps*side+ppl-1)%ppl, - start+pps*side - ] - ], - [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) for(j=[0:i-1]) - [ - laststart+lpps*side+j, - start+pps*side+j, - start+pps*side+1+j - ] - ], - (steps<2)?[]: [for(i=[2:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) for(j=[0:i-2]) - [ - laststart+lpps*side+j, - start+pps*side+j+1, - laststart+lpps*side+j+1 - ] - ], -//These faces fuse the top & bottom -//The steps'th row starts with 2*steps*(steps+1) -//The (steps+1)'th row starts with 2*steps*(steps+1)+4*steps - [for(side=[0:3]) let(start=2*steps*(steps+1)+4*(steps+1), - laststart=2*steps*(steps+1), - ppl=4*(steps+1),lppl=4*(steps+1), - pps=(steps+1),lpps=(steps+1) - ) for(j=[0:steps]) - - [ - laststart+lpps*side+j, - laststart+(lpps*side+lppl-1+j)%lppl, - start+(pps*side+ppl-1+j)%ppl, - start+pps*side+j - ] - ], -//And the top is just the bottom wound in reverse. - [[count-0,count-1,count-2,count-3]], - [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) - [ - count-(laststart+lpps*side), - count-(laststart+(lpps*side+lppl-1)%lppl), - count-(start+(pps*side+ppl-1)%ppl), - count-(start+pps*side) - ] - ], - [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) for(j=[0:i-1]) - [ - count-(laststart+lpps*side+j), - count-(start+pps*side+j), - count-(start+pps*side+1+j) - ] - ], - (steps<2)?[]: [for(i=[2:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), - ppl=4*(i+1),lppl=4*i, - pps=(i+1),lpps=i - ) - for(side=[0:3]) for(j=[0:i-2]) - [ - count-(laststart+lpps*side+j), - count-(start+pps*side+j+1), - count-(laststart+lpps*side+j+1) - ] - ] - ) - ] - ) - center?rcube:translate(size/2,rcube) -; - -rcube=(rounded_cube([3,2,1],1/3,fn=24,center=false)); -poly3d(rcube); - From a477917da1c0e23f2abc6963cae13e8c0aeea93a Mon Sep 17 00:00:00 2001 From: Nathan Hellweg Date: Tue, 30 Jan 2018 14:18:12 -0800 Subject: [PATCH 5/7] roundedcube out again --- subdivision.scad | 46 ++++++++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 18 deletions(-) diff --git a/subdivision.scad b/subdivision.scad index 28b0b8b..da66207 100644 --- a/subdivision.scad +++ b/subdivision.scad @@ -1,6 +1,7 @@ use // faces better be triangles... or else! + function subdivide_faces(n=1, poly) = let( points = poly[0], @@ -30,15 +31,13 @@ function subdivide_faces(n=1, poly) = n > 1 ? subdivide_faces(n-1, [allpoints, faces]) : n > 0 ? [allpoints,faces] : poly; //Utility function for splitting circular vectors. -function range (list,start,end)= +function circle_cut (list,start,end)= (end i ? v[i] + vsum(v, i+1) : [0,0,0]; - //Ineffictient (Order N^2) naive face triangulation function that works //by ear clipping: //Finds a convex vertex (order N) @@ -58,7 +57,7 @@ function triangulate_face(points,face)= (3==count)? [face] : - let(wd=winding_direction(points,face),cv=convexvertex(wd,points,face), + let(wd=face_winding(points,face),cv=convex_vertex(wd,points,face), pv=(count+cv-1)%count,nv=(cv+1)%count, p0=points[face[pv]],p1=points[face[cv]],p2=points[face[nv]], tests=[ @@ -66,29 +65,40 @@ function triangulate_face(points,face)= [cross(wd,p1-p0),cross(wd,p1-p0)*p1], [cross(wd,p2-p1),cross(wd,p2-p1)*p2] ], - eartest=pointinear(points,face,tests), + eartest=point_in_ear(points,face,tests), clipableear=(eartest[0]<0), diagonalpoint=eartest[1] ) (clipableear)? //There is no point inside the ear. flatten([ - [range(face,pv,nv)], - triangulate_face(points,range(face,nv,pv)) + [circle_cut(face,pv,nv)], + triangulate_face(points,circle_cut(face,nv,pv)) ]) : //If there is a point inside the ear, make a diagonal and clip along that. flatten([ - triangulate_face(points,range(face,cv,diagonalpoint)), - triangulate_face(points,range(face,diagonalpoint,cv)) + triangulate_face(points,circle_cut(face,cv,diagonalpoint)), + triangulate_face(points,circle_cut(face,diagonalpoint,cv)) ]) ; +function vsum(v_list,i=0)= + (i0)? (i+1)%count : - convexvertex(wd,points,face,i+1) + convex_vertex(wd,points,face,i+1) ://This should never happen since there is at least 1 convex vertex. undef ; @@ -104,21 +114,21 @@ function convexvertex(wd,points,face,i=0)= //The order of tests matters - This assumes Test 0 indicates which point is furthest in //the ear - and that point will form a diagonal with the tip of the ear. -function pointinear(points,face,tests,i=0)= +function point_in_ear(points,face,tests,i=0)= (iprev[0])? [test,i] : prev : - [checkpointinear(points[face[i]],tests),i] + [check_point_in_ear(points[face[i]],tests),i] ; -function checkpointinear (point,tests)= +function check_point_in_ear (point,tests)= let( result=[ (point*tests[0][0])-tests[0][1], From bee54b6cc215e0e2d786358a6cf994e7f82d132a Mon Sep 17 00:00:00 2001 From: Nathan Hellweg Date: Tue, 30 Jan 2018 14:18:58 -0800 Subject: [PATCH 6/7] roundedcube back in --- roundedcube.scad | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 roundedcube.scad diff --git a/roundedcube.scad b/roundedcube.scad new file mode 100644 index 0000000..da0baea --- /dev/null +++ b/roundedcube.scad @@ -0,0 +1,148 @@ +use + +/* Rounded cube using the cube/octahedron duality. */ + +function rounded_cube(size, r=0, center=false, fn=12)= + (!is_array(size))? + rounded_cube(size=[size,size,size],r=r,center=center,fn=fn) + :(r>=min(size[0],size[1],size[2])/2)? + rounded_cube(size=size,r=min(size[0],size[1],size[2])/2-.0001,center=center,fn=fn) + :(r<=0)? + cube(size,center=center) + : + let( + steps=(fn>0)?ceil(fn/4):1, + sx=size[0]/2-r, + sy=size[1]/2-r, + sz=size[2]/2-r, + da=90/steps, + count=4*(steps+1)*(steps+2)-1, + rcube=[ + flatten(concat( + [for (i=[0:steps]) + let( + z=r*(-cos(da*i))-sz, + l=r*sin(da*i), + dp=(i>0)?(90/i):0 + ) + concat( + [for(j=[0:i]) [sx+l*cos(dp*j),sy+l*sin(dp*j),z]], + [for(j=[0:i]) [-sx-l*sin(dp*j),sy+l*cos(dp*j),z]], + [for(j=[0:i]) [-sx-l*cos(dp*j),-sy-l*sin(dp*j),z]], + [for(j=[0:i]) [sx+l*sin(dp*j),-sy-l*cos(dp*j),z]] + ) + ], + [for (i=[steps:-1:0]) + let( + z=sz+r*cos(da*i), + l=r*sin(da*i), + dp=(i>0)?90/i:0 + ) + concat( + [for(j=[0:i]) [sx+l*cos(dp*j),sy+l*sin(dp*j),z]], + [for(j=[0:i]) [-sx-l*sin(dp*j),sy+l*cos(dp*j),z]], + [for(j=[0:i]) [-sx-l*cos(dp*j),-sy-l*sin(dp*j),z]], + [for(j=[0:i]) [sx+l*sin(dp*j),-sy-l*cos(dp*j),z]] + ) + ] + )), +//Each side on the i'th row has i+1 points +//The rows start with 0,4,8,12 ... 2*i*(i+1) +//Each side on the ith row has i+1 points + concat( + [[0,1,2,3]], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) + [ + laststart+lpps*side, + laststart+(lpps*side+lppl-1)%lppl, + start+(pps*side+ppl-1)%ppl, + start+pps*side + ] + ], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-1]) + [ + laststart+lpps*side+j, + start+pps*side+j, + start+pps*side+1+j + ] + ], + (steps<2)?[]: [for(i=[2:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-2]) + [ + laststart+lpps*side+j, + start+pps*side+j+1, + laststart+lpps*side+j+1 + ] + ], +//These faces fuse the top & bottom +//The steps'th row starts with 2*steps*(steps+1) +//The (steps+1)'th row starts with 2*steps*(steps+1)+4*steps + [for(side=[0:3]) let(start=2*steps*(steps+1)+4*(steps+1), + laststart=2*steps*(steps+1), + ppl=4*(steps+1),lppl=4*(steps+1), + pps=(steps+1),lpps=(steps+1) + ) for(j=[0:steps]) + + [ + laststart+lpps*side+j, + laststart+(lpps*side+lppl-1+j)%lppl, + start+(pps*side+ppl-1+j)%ppl, + start+pps*side+j + ] + ], +//And the top is just the bottom wound in reverse. + [[count-0,count-1,count-2,count-3]], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) + [ + count-(laststart+lpps*side), + count-(laststart+(lpps*side+lppl-1)%lppl), + count-(start+(pps*side+ppl-1)%ppl), + count-(start+pps*side) + ] + ], + [for(i=[1:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-1]) + [ + count-(laststart+lpps*side+j), + count-(start+pps*side+j), + count-(start+pps*side+1+j) + ] + ], + (steps<2)?[]: [for(i=[2:steps]) let(start=2*i*(i+1),laststart=2*i*(i-1), + ppl=4*(i+1),lppl=4*i, + pps=(i+1),lpps=i + ) + for(side=[0:3]) for(j=[0:i-2]) + [ + count-(laststart+lpps*side+j), + count-(start+pps*side+j+1), + count-(laststart+lpps*side+j+1) + ] + ] + ) + ] + ) + center?rcube:translate(size/2,rcube) +; + +rcube=(rounded_cube([3,2,1],1/3,fn=24,center=false)); +poly3d(rcube); + From a934d610e5a4254c587262e6ea9bbc346ec30ec3 Mon Sep 17 00:00:00 2001 From: NateTG Date: Mon, 19 Feb 2018 17:15:20 -0800 Subject: [PATCH 7/7] Update subdivision.scad Off-by-one error --- subdivision.scad | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/subdivision.scad b/subdivision.scad index da66207..e417f46 100644 --- a/subdivision.scad +++ b/subdivision.scad @@ -99,7 +99,7 @@ function face_winding(points,face)= ; function convex_vertex(wd,points,face,i=0)= - let(count=len(face)-1, + let(count=len(face), p0=points[face[i]],p1=points[face[(i+1)%count]],p2=points[face[(i+2)%count]] ) (len(face)>i)?