Dan Shriver tabbydan at gmail.com
Fri Jul 5 09:42:54 EDT 2019

```use <list-comprehension/skin.scad>;

function echoit(x) = echo(x) x;
//function echoit2(y,x) = echo(y,x) x; //debug version
function echoit2(y,x) =  x; //debug off
function echoit3(y,x) = x; //debug off
//function echoit4(y,x) = echo(y,x) x; //debug version
function echoit4(y,x) =  x; //debug off
function echoit5(y,x) = echo(y,x) x; //debug

function partitionNum(pn,points) =
(pn < (points-2)/4) ? 0 :         //OUTER RIGHT
(pn < (points-2)/4 + 1)  ? 1 :    //OUTER TOP
(pn < (points-2)/2 + 1) ? 2:      //OUTER LEFT
(pn < (3*(points-2))/4 + 1) ? 3:  //INNER LEFT
(pn < (3*(points-2))/4 + 2) ? 4:  //INNER TOP
5;                                // INNER RIGHT

function subPointNum(points, pointNum, partition) =
[pointNum,
1, //doesn't matter
((points-2)/2) - pointNum,
pointNum - points/2,
1, //doesn't matter
((points-1) - pointNum)]
[partition];

//one more point in the outer arcs one less in the inner
function partitionNumNc(pn,points,solid) = (solid) ? (pn < (points)/2) ? 0
:         //OUTER RIGHT
(pn == (points)/2)  ? 1 :    //OUTER TOP
2 :
(pn < (points)/4) ? 0 :         //OUTER RIGHT
(pn == (points)/4)  ? 1 :    //OUTER TOP
(pn < ((points)/2)+1) ? 2:      //OUTER LEFT
(pn < (3*points)/4) ? 3:  //INNER LEFT
(pn == (3*points)/4) ? 4:  //INNER TOP
5                                // INNER RIGHT
;

function subPointNumNc(points, pointNum, partition) =
[pointNum,
1, //doesn't matter
((points)/2) - pointNum,
pointNum - (points/2+1),
1, //doesn't matter
((points-1) - pointNum)]
[partition];

//a roman arch with 4n + 4 points to match an ogee
//no cap arch with 8n points
//use a number of points that is a multiple of 8
function archXNc(radius, thickness, angle, pointNum, points, solid) =
partition = partitionNumNc(pointNum,points,solid),
subPoint = subPointNumNc(points, pointNum, partition),
steps = (pointNum < (points/2)) ? (((points)/4)) : (((points)/4) - 1))
0,
PTS - 2 EXP + 1
thickness)*cos(angle))), //PTS -2  EXP +1
0,
(radius - thickness) * cos((angle/steps) *  subPoint) -
(radius-thickness)*cos(angle) //PTS - 2 EXP +2
]
[partition];

function archYNc(radius, thickness, angle, pointNum, points, solid) =
partition = partitionNumNc(pointNum,points,solid),
subPoint = subPointNumNc(points, pointNum, partition),
steps = (pointNum < (points/2)) ? ((points)/4) : ((points)/4) - 1)
(radius - thickness) * sin( angle/steps * subPoint),
]
[partition];

//use this with a no-cap ogee as this works out to
//be 4n +  4 points which meshes with 8n of a no cap ogee
// 8, 12, 16, 20,....
// you will have to use ODD N values to match with
// a linear progression of 8n
// (4m)+ 4 = 8n for 1 on both sides 3m=2n; 5m = 3n etc
// This function actuall works on ugly numbers 6 + 4(n) points: 10, 14, 18,
22 ...
function romanArchNc(radius, thickness, angle, pointCnt, solid = false)
= (solid) ? [ for (i = [0:1:(pointCnt/2 -1)]) [archXNc(radius, thickness,
angle, i, pointCnt, solid), archYNc(radius, thickness, angle, i, pointCnt,
solid)] ] : [ for (i = [0:1:(pointCnt-1)]) [archXNc(radius, thickness,
angle, i, pointCnt, solid), archYNc(radius, thickness, angle, i, pointCnt,
solid)] ];

//the second half is missing one point, figure it out...
//romanArch(20, 1, 70, 200);

//8n (if capwidth = 0); 8n + 2 otherwise
= false, capwidth = 0.0, apexangle = 45.0) =
let(
// Angle extended by the arcs
lowerphi = 180.0 - acos((0.5*(width - capwidth) - lowerradius -
upperphi = lowerphi - 0.5 * apexangle,
apexhalf = 0.5 * apexangle,

// Number of points per lower arc
lowerpoints = echoit2("lowerpoints ",round((capwidth > 0.0) ?
lowerphi*(points-4)/(8*lowerphi-4*apexangle) :
lowerphi*(points-2)/(8*lowerphi-4*apexangle))),

// Actual number of points in the upper arc
uppertemp = echoit2("uppertemp ",round((capwidth > 0.0) ?
(lowerphi-apexangle)*(points-4)/(8*lowerphi-4*apexangle) :
(lowerphi-apexangle)*(points-2)/(8*lowerphi-4*apexangle))),
targetpoints = echoit2("targetpoints ", (apexangle > 0.0) ? points - 5
: points - 2),
upperpoints = echoit2("upperpoints ",(targetpoints - 4*(lowerpoints +
uppertemp) >= -1) ? uppertemp + 1 : uppertemp),

// Key horizontal coordinates. Note: w0=x1, w6=x2
w0 = 0.5*width - thickness - lowerradius,
w1 = 0.5*capwidth,
w2 = w0 + lowerradius * cos(lowerphi),
w3 = w0 + (lowerradius + thickness) * cos(lowerphi),
w5 = w0 + lowerradius + thickness,

// Key vertical coordinates. Note: y1=h0=0, y2=h6
h5 = h6 - upperradius * sin(apexhalf),
h4 = h5 - 0.5*capwidth * tan(apexhalf),
h3 = h6 - (upperradius + thickness) * sqrt(1.0 - w6*w6 / ((upperradius
+ thickness) * (upperradius + thickness))),
h2 = (lowerradius + thickness) * sin(lowerphi),
h0 = 0.0,
height = (apexangle > 0.0) ? (h5 + 0.5*capwidth / tan(apexhalf)) : h5,

// We use the same number of points for the upper inner arc,
// even though it is a bit smaller angle.
innertheta = acos(w6 / (upperradius + thickness)),
innerphi = lowerphi - innertheta,

// Lower Right Outer arc
lro = echoit3("lro ",[ for (i = [0:1:lowerpoints-1]) [ w0 +
(lowerradius + thickness) * cos(i * lowerphi / lowerpoints), h0 +
(lowerradius + thickness) * sin(i * lowerphi / lowerpoints) ] ]),
// Upper Right Outer arc
uro = echoit3("uro ",[ for (i = [upperpoints-1:-1:0]) [ w6 -
upperradius * cos(apexhalf + i * upperphi / upperpoints), h6 - upperradius
* sin(apexhalf + i * upperphi / upperpoints) ] ]),
// Cap
cap = (capwidth > 0.0) ? [ [ w1, h5 ], [ 0, height ] ] : [],
// Upper Left Outer arc
ulo = echoit3("ulo ",[ for (i = [0:1:upperpoints-1]) [ -w6 +
upperradius * cos(apexhalf + i * upperphi / upperpoints), h6 - upperradius
* sin(apexhalf + i * upperphi / upperpoints) ] ]),
// Lower Left Outer arc
//incorrectly 4 pts
//changing loop first contition to lowerpoints-1 from "lowerpoints"
llo = echoit3("llo ",[ for (i = [lowerpoints-1:-1:0]) [ -w0 -
(lowerradius + thickness) * cos(i * lowerphi / lowerpoints), h0 +
(lowerradius + thickness) * sin(i * lowerphi / lowerpoints) ] ]),
// Lower Left Inner arc
lli = (solid) ? [] : [ for (i = [0:1:lowerpoints-1]) [ -w0 -
lowerradius * cos(i * lowerphi / lowerpoints), h0 + lowerradius * sin(i *
lowerphi / lowerpoints) ] ],
// Upper Left Inner arc
uli = (solid) ? [] : [ for (i = [upperpoints-1:-1:0]) [ -w6 +
(upperradius + thickness) * cos(innertheta + i * innerphi / upperpoints),
h6 - (upperradius + thickness) * sin(innertheta + i * innerphi /
upperpoints) ] ],
// Upper Right Inner arc
uri = (solid) ? [] : [ for (i = [0:1:upperpoints-1]) [ w6 -
(upperradius + thickness) * cos(innertheta + i * innerphi / upperpoints),
h6 - (upperradius + thickness) * sin(innertheta + i * innerphi /
upperpoints) ] ],
// Lower Right Inner arc
lri = (solid) ? [] : [ for (i = [lowerpoints-1:-1:0]) [ w0  +
lowerradius * cos(i * lowerphi / lowerpoints), h0 + lowerradius * sin(i *
lowerphi / lowerpoints) ] ]
)
concat(lro, uro, cap, ulo, llo, lli, uli, uri, lri);

//this is used to make half of an ogee arch
// it is a "pathway" on which the real arches are
// centered on in arch2()
capwidth = 0.0, apexangle = 45.0) =
let(
// Angle extended by the arcs
lowerphi = 180.0 - acos((0.5*(width - capwidth) - lowerradius -
upperphi = lowerphi - 0.5 * apexangle,
apexhalf = 0.5 * apexangle,

// Number of points per lower arc
lowerpoints = round((capwidth > 0.0) ?
lowerphi*(points-4)/(8*lowerphi-4*apexangle) :
lowerphi*(points-2)/(8*lowerphi-4*apexangle)),

// Actual number of points in the upper arc
uppertemp = round((capwidth > 0.0) ?
(lowerphi-apexangle)*(points-4)/(8*lowerphi-4*apexangle) :
(lowerphi-apexangle)*(points-2)/(8*lowerphi-4*apexangle)),
targetpoints = (apexangle > 0.0) ? points - 5 : points - 2,
upperpoints = (targetpoints - 4*(lowerpoints + uppertemp) >= -1) ?
uppertemp + 1 : uppertemp,

// Key horizontal coordinates. Note: w0=x1, w6=x2
w0 = 0.5*width - thickness - lowerradius,
w1 = 0.5*capwidth,
w2 = w0 + lowerradius * cos(lowerphi),
w3 = w0 + (lowerradius + thickness) * cos(lowerphi),
w5 = w0 + lowerradius + thickness,

// Key vertical coordinates. Note: y1=h0=0, y2=h6
h5 = h6 - upperradius * sin(apexhalf),
h4 = h5 - 0.5*capwidth * tan(apexhalf),
h3 = h6 - (upperradius + thickness) * sqrt(1.0 - w6*w6 / ((upperradius
+ thickness) * (upperradius + thickness))),
h2 = (lowerradius + thickness) * sin(lowerphi),
h0 = 0.0,
height = (apexangle > 0.0) ? (h5 + 0.5*capwidth / tan(apexhalf)) : h5,

// We use the same number of points for the upper inner arc,
// even though it is a bit smaller angle.
innertheta = acos(w6 / (upperradius + thickness)),
innerphi = lowerphi - innertheta,

// Lower Right Outer arc
lro = [ for (i = [0:1:lowerpoints-1]) [ w0 + (lowerradius + thickness)
* cos(i * lowerphi / lowerpoints), 0, h0 + (lowerradius + thickness) *
sin(i * lowerphi / lowerpoints) ] ],
// Upper Right Outer arc
uro = [ for (i = [upperpoints-1:-1:0]) [ w6 - upperradius *
cos(apexhalf + i * upperphi / upperpoints), 0, h6 - upperradius *
sin(apexhalf + i * upperphi / upperpoints) ] ],
// Cap
cap = (capwidth > 0.0) ? [ [ w1, 0, h5 ], [ 0, 0, height ] ] : [],
// Upper Left Outer arc
ulo = [ for (i = [0:1:upperpoints-1]) [ -w6 + upperradius *
cos(apexhalf + i * upperphi / upperpoints), 0, h6 - upperradius *
sin(apexhalf + i * upperphi / upperpoints) ] ],
// Lower Left Outer arc
llo = [ for (i = [lowerpoints:-1:0]) [ -w0 - (lowerradius + thickness)
* cos(i * lowerphi / lowerpoints), 0, h0 + (lowerradius + thickness) *
sin(i * lowerphi / lowerpoints) ] ]
)
concat(lro, uro, cap, ulo, llo);

function stupid(i) = (i==1) ? ogeepoly(65,3,60,60,100,1,10) : romanArch(70,
3, 62, 200);

//makes an arch interpolation between a wider roman
//arch and ogee arch, uses sin() so the transition
//is curved
function waveOut(i,verticies,thickness,solid) = abs(sin(i)) *
romanArchNc(65, thickness, 70, echoit5("verticies",verticies),solid) + (1 -
abs(sin(i))) *
ogeepoly(65,thickness,60,60,echoit5("verticies",verticies),solid,0.0,0);//was
1,10 at end

//makes an arch interpolation between a narrow roman
//arch and ogee arch, uses sin() so the transition
//is curved
function waveIn(i,verticies,thickness,solid) = abs(sin(i)) *
romanArchNc(95, thickness, 40, echoit5("verticies",verticies),solid) + (1 -
abs(sin(i))) *
ogeepoly(65,thickness,60,60,echoit5("verticies",verticies),solid,0.0,0);//was
1,10 at end

//alternates wave in and wave out...
function wave(i,verticies=200,thickness,solid) = (i < 31) ?
waveOut(echoit4("<31",(i*6)),echoit5("verticies",verticies),thickness,solid)
:
(i < 61) ?
waveIn(echoit4("<61",(180-((i-30)*6))),verticies,thickness,solid) :
(i < 91) ?
waveOut(echoit4("<91",(i-60)*6),verticies,thickness,solid) :

waveIn(echoit4("last",180-((i-90)*6)),verticies,thickness,solid);

function archselect(i,verticies=160,thickness,solid) = (i == 0) ?
romanArchNc(95, thickness, 40, verticies,solid) + (1 - abs(sin(i))) *
ogeepoly(65,thickness,60,60,verticies,solid,0.0,0)
:ogeepoly(65,thickness,60,60,verticies,solid,0.0,0);

//this makes the shape I want a transtion between
//roman and ogee arches on a pathway that is half
//an ogee arch
//I'd use 6 of these to make the hallways I want
//16 verticies simplifies things
module arches2(verticies=192, thickness = 8, solid = false) {

yxzpath = ogeepolyPath(650, 3, 600, 600, 420, 1, 10);

//echo(yxzpath);
//echo("blah");
//echo(yxzpath);

skin([
for (i=[1 : 1 :  105])
transform(translation(yxzpath[i]) * rotation([0,0,0]),
wave(i,verticies,thickness,solid))
]);
}

//this does one fully roman arch and one fully
// ogee arch (or it should) for testing
module arches5(verticies=160, thickness = 4, solid = false) {
skin([
for (i=[0 : 1 : 1])
transform(translation([0,0,(i*90)]) * rotation([0,0,0]),
archselect(i, verticies, thickness, solid))
]);
}

//for testing, does the arches transitioning
//but on a linear path
module arches6(verticies=192, thickness = 8, solid = false) {
skin([
for (i=[1 : 1 : 105])
transform(translation([0,0,i]) * rotation([0,0,0]),
wave(i,verticies,thickness,solid))
]);
}

//for testing
//do fewer interpolations to find where it goes wrong
module arches7(verticies=192, thickness = 8, solid = false) {

yxzpath = ogeepolyPath(650, 3, 600, 600, 420, 1, 10);

//echo(yxzpath);
//echo("blah");
//echo(yxzpath);

skin([
for (i=[90 : 1 :  105])
transform(translation(yxzpath[i]) * rotation([0,0,0]),
wave(i,verticies,thickness,solid))
]);
}

//for testing
/*uses wave but on a linear path to make it easier to view
allows you to select how many slices to use
*/
module arches8(verticies=192, thickness = 8, solid = false, start = 0, end
= 105) {

skin([
for (i=[start : 1 :  end])
transform(translation([0,0,(i-start)]) * rotation([0,0,0]),
wave(i,verticies,thickness,solid))
]);
}

//for testing
//another linear path with wave in and out
module arches4(verticies=190) {

skin([
for (i=[1 : 1 : 90])
transform(translation([0,0,i*0.5]) * rotation([0,0,0]), wave(i,verticies))
]);
}

//for testing
//another linear path this one with just wave out
module arches3(start,end,verticies=190) {

skin([
for (i=[start : 1 : end])
transform(translation([0,0,i*0.5]) * rotation([0,0,0]),
waveOut(i,verticies))
]);
}

//polygon test of roman arch or ogee poly
//they both look ok with the same number of verticies
//(10,14,18,22,26.... 6+4(n))
//but the verticies must not be in the same order
//or number because if you do "arches3(0,90,22);"
//there is a twist...
//pts = romanArch(65, 3, 70, 22);
//pts = ogeepoly(65,3,60,60,22,0.0,0);
//polygon(pts);

//pts = romanArchNc(65, 3, 70, 24);
//polygon(pts);

//90 goes from ogee to roman completely
//arches3(0,90,24);

//half the passageway
//arches2(64,4);

//arches5(16,2);

//polygon(romanArchNc(65, 3, 70, 16));

//polygon(ogeepoly(65,3,60,60,16,0,10));

//this test case works
/*
union () {
arches5(48);

translate([0,0,90]) {cube([80,80,80], true); }
}
*/

/*this test case seems to work:
does give the disturbing warning

"DEPRECATED: Using ranges of the form [begin:end] with begin value greater
than the end value is deprecated.
Rendering Polygon Mesh using CGAL...
ERROR: Unable to convert point at index 1 to a vec3 of numbers
PolySet has nonplanar faces. Attempting alternate construction"
*/
/*
difference() {
arches5(24);
mirror([1,0,1]) {
arches5(24,true); //subtract a SOLID version
}
}
mirror([1,0,1]) {
arches5(24);
}
*/

//works
//arches6(8,2);

//works
/*
union () {
arches6(8,2);

translate([0,0,90]) {cube([80,80,80], true); }
}
*/

//this test case says non-planiar facets, but renders
//24 verticies try lower
/*
difference() {
arches6(24,2);
mirror([1,0,1]) {
arches6(24,2,true); //subtract a SOLID version
}
}
mirror([1,0,1]) {
arches6(24,2);
}
*/

//translate([0,0,750]) {cube([80,80,80], true); }

//a test of unioning half the passageway with a cube
//gets errors

//works
//arches2(24,2);

//does not work
/* "
Rendering Polygon Mesh using CGAL...
ERROR: CGAL error in CGAL_Nef_polyhedron3(): CGAL ERROR: assertion
violation! Expr: e_below != SHalfedge_handle() File:
/opt/mxe/usr/x86_64-w64-mingw32.static.posix/include/CGAL/Nef_3/SNC_FM_decorator.h
Line: 426
Geometries in cache: 17
Geometry cache size in bytes: 2167192
CGAL Polyhedrons in cache: 4
CGAL cache size in bytes: 11344
Total rendering time: 0 hours, 0 minutes, 4 seconds
Top level object is a 3D object:
Simple:        yes
Vertices:        8
Halfedges:      24
Edges:          12
Halffacets:     12
Facets:          6
Volumes:         2
Rendering finished.
"
*/
/*
union () {
arches2(16,4);

translate([0,0,750]) {cube([80,80,80], true); }
}
*/

//arches7(16);

//arches8(16,8,false,1,3);

//this works odd
/*
union() {
arches8(16,8,false,0,105);
translate([0,20,00]) {cube([50,50,50], true); }
}
*/

//blows up:
/*
union() {
arches7(16,4);
//for the first 15 translate 300, 0, 10 works nice
translate([0,0,600]) {cube([40,40,40], true); }
}
*/
//arches2(16,4);
//translate([0,0,600]) {cube([80,80,80], true); }

//arches2(16,2);

//does not work
/*
Rendering Polygon Mesh using CGAL...
ERROR: CGAL error in CGAL_Nef_polyhedron3(): CGAL ERROR: assertion
violation! Expr: e_below != SHalfedge_handle() File:
/opt/mxe/usr/x86_64-w64-mingw32.static.posix/include/CGAL/Nef_3/SNC_FM_decorator.h
Line: 426
ERROR: CGAL error in CGAL_Nef_polyhedron3(): CGAL ERROR: assertion
violation! Expr: e_below != SHalfedge_handle() File:
/opt/mxe/usr/x86_64-w64-mingw32.static.posix/include/CGAL/Nef_3/SNC_FM_decorator.h
Line: 426
Geometries in cache: 21
Geometry cache size in bytes: 3129336
CGAL Polyhedrons in cache: 5
CGAL cache size in bytes: 11344
Total rendering time: 0 hours, 0 minutes, 8 seconds
Rendering finished.
*/
/*
arches2(16,2);
mirror([0,0,1]) {
arches2(16,2);
}
*/

//does not work either
/*
difference() {
arches2(16,4);
mirror([0,0,1]) {
arches2(16,4,true); //subtract a SOLID version
}
}
*/

//arches2(16);

//making a full passageway, gets errors
/*
gets "
DEPRECATED: Using ranges of the form [begin:end] with begin value greater
than the end value is deprecated. "
partway through the verticies calculation

then at the end it has "

Rendering Polygon Mesh using CGAL...
Geometries in cache: 21
Geometry cache size in bytes: 3129336
CGAL Polyhedrons in cache: 5
CGAL cache size in bytes: 11344
Total rendering time: 0 hours, 0 minutes, 6 second
"
*/
/*
difference() {
arches2(16);
mirror([0,0,1]) {
arches2(16,true); //subtract a SOLID version
}
}
mirror([0,0,1]) {
arches2(16);
}
*/

//polygon(ogeepoly(65,3,60,60,200,0.0,0));

/*
polygon(ogeepoly(65,3,60,60,200,1,10));
polygon(romanArch(65, 3, 70, 200));
polygon(romanArch(95, 3, 40, 200));
*/

On Thu, Jul 4, 2019 at 11:44 PM MichaelAtOz <oz.at.michael at gmail.com> wrote:

> DanS wrote
> > MichaelAtOz:
> > I can show the code to people but it isn't pretty and rightfully people
> > have said in the past "I don't want to debug that"
>
> I'll have a first look, no guarantees tho.
>
>
>
> -----
> Admin - email* me if you need anything, or if I've done something stupid...
>
> * click on my MichaelAtOz label, there is a link to email me.
>
> Unless specifically shown otherwise above, my contribution is in the
> Public Domain; to the extent possible under law, I have waived all
> copyright and related or neighbouring rights to this work. Obviously
> inclusion of works of previous authors is not included in the above.
>
> The TPP is no simple “trade agreement.”   Fight it!
> http://www.ourfairdeal.org/   time is running out!
> --