Missing parameter in drawPlate()

Missing parameter in drawPlate()

/**
 * @license
 * MIT License
 *
 * Copyright (c) 2017 Jean-Sebastien CONAN
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/**
 * Part of the camelSCAD library.
 *
 * Rounded shapes.
 *
 * @package shape/3D
 * @author jsconan
 */

/**
 * Computes the size of a 3D rounded shape.
 *
 * @param Number|Vector [r] - The radius of the rounded part or a vector that contains radius for each dimensions.
 * @param Number|Vector [d] - The diameter of the rounded part or a vector that contains diameters for each dimensions.
 * @param Number [rx] - The length radius.
 * @param Number [ry] - The width radius.
 * @param Number [rz] - The height radius.
 * @param Number [dx] - The length diameter.
 * @param Number [dy] - The width diameter.
 * @param Number [dz] - The height diameter.
 * @returns Vector - Returns the radius vector.
 */
function sizeRounded3D(r, d, rx, ry, rz, dx, dy, dz) =
    let(
        r = apply3D(r, rx, ry, rz),
        d = apply3D(d, dx, dy, dz)
    )
    [
        d[0] && !rx ? d[0] / 2 : r[0],
        d[1] && !ry ? d[1] / 2 : r[1],
        d[2] && !rz ? d[2] / 2 : r[2]
    ]
;

/**
 * Computes the size of an arch box.
 *
 * @param Number|Vector [size] - The size of the arch.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizeArchBox(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[1]),
            divisor(s[2])
        ],
        horRadius = size[0] / 2,
        radius = [
            horRadius,
            min(size[1], or(c[1], horRadius))
        ]
    )
    [ size, radius ]
;

/**
 * Computes the size of a stadium shape.
 *
 * @param Number|Vector [size] - The size of the stadium.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizeSlot(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[1] * 2),
            divisor(s[2])
        ],
        horRadius = size[0] / 2,
        radius = [
            horRadius,
            min(size[1] / 2, or(c[1], horRadius))
        ]
    )
    [ size, radius ]
;

/**
 * Computes the size of a cushion shape.
 *
 * @param Number|Vector [size] - The size of the rounded rectangle.
 * @param Number|Vector [r] - The radius of the corners or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter of the corners  or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius of the corners.
 * @param Number [ry] - The vertical radius of the corners.
 * @param Number [dx] - The horizontal diameter of the corners.
 * @param Number [dy] - The vertical diameter of the corners.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizeCushion(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[1] * 2),
            divisor(s[2])
        ],
        radius = [
            min(size[0] / 2, c[0]),
            min(size[1] / 2, c[1])
        ]
    )
    [ size, radius[0] && radius[1] ? radius : [0, 0] ]
;

/**
 * Computes the size of a bullet shape.
 *
 * @param Number|Vector [size] - The size of the bullet.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizeBullet(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[0] * 2),
            divisor(s[2] ? s[2] : c[1])
        ],
        horRadius = max(size[0], size[1]) / 2,
        radius = [
            horRadius,
            min(size[2], or(c[1], horRadius))
        ]
    )
    [ size, radius ]
;

/**
 * Computes the size of a pill shape.
 *
 * @param Number|Vector [size] - The size of the pill.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizePill(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[0] * 2),
            divisor(s[2] ? s[2] : c[1] * 2)
        ],
        horRadius = max(size[0], size[1]) / 2,
        radius = [
            horRadius,
            min(size[2] / 2, or(c[1], horRadius))
        ]
    )
    [ size, radius ]
;

/**
 * Computes the size of a peg shape.
 *
 * @param Number|Vector [size] - The size of the peg.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizePeg(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[0] * 2),
            divisor(s[2] ? s[2] : c[1] * 2)
        ],
        radius = [
            min(max(size[0], size[1]) / 2, c[0]),
            min(size[2] / 2, c[1])
        ]
    )
    [ size, radius[0] && radius[1] ? radius : [0, 0] ]
;

/**
 * Computes the size of a plate shape.
 *
 * @param Number|Vector [size] - The size of the plate.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizePlate(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[0] * 2),
            divisor(s[2] ? s[2] : c[1] * 2)
        ],
        verRadius = size[2] / 2,
        radius = [
            min(max(size[0], size[1]) / 2, or(c[0], verRadius)),
            verRadius
        ]
    )
    [ size, radius ]
;

/**
 * Computes the points that draw the sketch of a bullet shape.
 *
 * @param Number|Vector [size] - The size of the bullet.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[]
 */
function drawBullet(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        specs = sizeBullet(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy),
        size = specs[0],
        radius = specs[1],
        center = [
            0, size[2] - radius[1]
        ],
        points = arc(r=radius, o=center, a=RIGHT)
    )
    complete(points, [radius[0], 0], [0, 0])
;

/**
 * Computes the points that draw the sketch of a pill shape.
 *
 * @param Number|Vector [size] - The size of the pill.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[]
 */
function drawPill(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        specs = sizePill(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy),
        size = specs[0],
        radius = specs[1],
        center = [
            0, size[2] / 2 - radius[1]
        ]
    )
    center == [0, 0] ? arc(r=radius, a1=-RIGHT, a2=RIGHT)
   :concat(
        arc(r=radius, o=-center, a=RIGHT, a1=-RIGHT),
        arc(r=radius, o=center, a=RIGHT)
    )
;

/**
 * Computes the points that draw the sketch of a peg shape.
 *
 * @param Number|Vector [size] - The size of the peg.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[]
 */
function drawPeg(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        specs = sizePeg(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy),
        size = specs[0],
        radius = specs[1],
        right = max(size[0], size[1]) / 2,
        top = size[2] / 2,
        center = [
            right - radius[0],
            top - radius[1]
        ]
    )
    radius == [0, 0] ? [ [right, top], [0, top], [0, -top], [right, -top] ]
   :center == [0, 0] ? arc(r=radius, a1=-RIGHT, a2=RIGHT)
   :complete(
        concat(
            arc(r=radius, o=[center[0], -center[1]], a1=QUADRANT_3, a2=QUADRANT_4),
            arc(r=radius, o=center, a1=0, a2=QUADRANT_1)
        ),
        [0, -top],
        [0, top]
    )
;

/**
 * Computes the points that draw the sketch of a plate shape.
 *
 * @param Number|Vector [size] - The size of the plate.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[]
 */
function drawPlate(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        specs = sizePlate(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy),
        size = specs[0],
        radius = specs[1],
        center = [
            max(size[0], size[1]) / 2 - radius[0], 0
        ],
        points = arc(r=radius, o=center, a1=-RIGHT, a2=RIGHT)
    )
    center == [0, 0] ? points
   :complete(points, -[0, radius[1]], [0, radius[1]])
;

/**
 * Creates an arch box at the origin.
 *
 * @param Number|Vector [size] - The size of the arch.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @param Boolean [center] - Whether or not center the box on the vertical axis.
 */
module archBox(size, r, d, l, w, h, rx, ry, dx, dy, center) {
    size = sizeArchBox(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    linear_extrude(height=size[0][2], center=center, convexity=10) {
        arch(size[0], size[1]);
    }
}

/**
 * Creates a slot shape at the origin.
 *
 * @param Number|Vector [size] - The size of the stadium.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @param Boolean [center] - Whether or not center the box on the vertical axis.
 */
module slot(size, r, d, l, w, h, rx, ry, dx, dy, center) {
    size = sizeSlot(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    linear_extrude(height=size[0][2], center=center, convexity=10) {
        stadium(size[0], size[1]);
    }
}

/**
 * Creates a cushion shape at the origin.
 *
 * @param Number|Vector [size] - The size of the rounded rectangle.
 * @param Number|Vector [r] - The radius of the corners or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter of the corners  or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius of the corners.
 * @param Number [ry] - The vertical radius of the corners.
 * @param Number [dx] - The horizontal diameter of the corners.
 * @param Number [dy] - The vertical diameter of the corners.
 * @param Boolean [center] - Whether or not center the box on the vertical axis.
 */
module cushion(size, r, d, l, w, h, rx, ry, dx, dy, center) {
    size = sizeCushion(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    linear_extrude(height=size[0][2], center=center, convexity=10) {
        roundedRectangle(size[0], size[1]);
    }
}

/**
 * Creates a bullet shape at the origin.
 *
 * @param Number|Vector [size] - The size of the bullet.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 */
module bullet(size, r, d, l, w, h, rx, ry, dx, dy) {
    specs = sizeBullet(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    resize(specs[0]) {
        rotate_extrude(convexity=10) {
            polygon(
                points=drawBullet(size=specs[0], r=specs[1]),
                convexity=10
            );
        }
    }
}

/**
 * Creates a pill shape at the origin.
 *
 * @param Number|Vector [size] - The size of the pill.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 */
module pill(size, r, d, l, w, h, rx, ry, dx, dy) {
    specs = sizePill(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    resize(specs[0]) {
        rotate_extrude(convexity=10) {
            polygon(
                points=drawPill(size=specs[0], r=specs[1]),
                convexity=10
            );
        }
    }
}

/**
 * Creates a peg shape at the origin.
 *
 * @param Number|Vector [size] - The size of the peg.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 */
module peg(size, r, d, l, w, h, rx, ry, dx, dy) {
    specs = sizePeg(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    resize(specs[0]) {
        rotate_extrude(convexity=10) {
            polygon(
                points=drawPeg(size=specs[0], r=specs[1]),
                convexity=10
            );
        }
    }
}

/**
 * Creates a plate shape at the origin.
 *
 * @param Number|Vector [size] - The size of the plate.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 */
module plate(size, r, d, l, w, h, rx, ry, dx, dy) {
    specs = sizePlate(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    resize(specs[0]) {
        rotate_extrude(convexity=10) {
            polygon(
                points=drawPlate(size=specs[0], r=specs[1]),
                convexity=10
            );
        }
    }
}

/**
 * Creates a rounded corner wedge at the origin.
 * For now the function can only handle square corner.
 *
 * @param Number [size] - The size of the corner.
 * @param Number [r] - The radius of the round.
 * @param Number [h] - The height of the solid.
 * @param Number [d] - The diameter of the round.
 * @param String|Vector [p] - The position of the corner, as a cardinal point (default: "ne", aka North East).
 * @param Boolean [convex] - Whether makes a convex corner (default: false).
 * @param Number [adjust] - An adjust value added to the size in order to fix wall alignment issue.
 * @param Boolean [center] - Whether or not center the solid on the vertical axis.
 */
module roundedCornerWedge(size, r, h, d, p, convex, adjust, center) {
    linear_extrude(height=divisor(h), center=center, convexity=10) {
        roundedCorner(size=size, r=r, d=d, p=p, convex=convex, adjust=adjust);
    }
}

/**
 * @license
 * MIT License
 *
 * Copyright (c) 2017 Jean-Sebastien CONAN
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/**
 * Part of the camelSCAD library.
 *
 * Rounded shapes.
 *
 * @package shape/3D
 * @author jsconan
 */

/**
 * Computes the size of a 3D rounded shape.
 *
 * @param Number|Vector [r] - The radius of the rounded part or a vector that contains radius for each dimensions.
 * @param Number|Vector [d] - The diameter of the rounded part or a vector that contains diameters for each dimensions.
 * @param Number [rx] - The length radius.
 * @param Number [ry] - The width radius.
 * @param Number [rz] - The height radius.
 * @param Number [dx] - The length diameter.
 * @param Number [dy] - The width diameter.
 * @param Number [dz] - The height diameter.
 * @returns Vector - Returns the radius vector.
 */
function sizeRounded3D(r, d, rx, ry, rz, dx, dy, dz) =
    let(
        r = apply3D(r, rx, ry, rz),
        d = apply3D(d, dx, dy, dz)
    )
    [
        d[0] && !rx ? d[0] / 2 : r[0],
        d[1] && !ry ? d[1] / 2 : r[1],
        d[2] && !rz ? d[2] / 2 : r[2]
    ]
;

/**
 * Computes the size of an arch box.
 *
 * @param Number|Vector [size] - The size of the arch.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizeArchBox(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[1]),
            divisor(s[2])
        ],
        horRadius = size[0] / 2,
        radius = [
            horRadius,
            min(size[1], or(c[1], horRadius))
        ]
    )
    [ size, radius ]
;

/**
 * Computes the size of a stadium shape.
 *
 * @param Number|Vector [size] - The size of the stadium.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizeSlot(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[1] * 2),
            divisor(s[2])
        ],
        horRadius = size[0] / 2,
        radius = [
            horRadius,
            min(size[1] / 2, or(c[1], horRadius))
        ]
    )
    [ size, radius ]
;

/**
 * Computes the size of a cushion shape.
 *
 * @param Number|Vector [size] - The size of the rounded rectangle.
 * @param Number|Vector [r] - The radius of the corners or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter of the corners  or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius of the corners.
 * @param Number [ry] - The vertical radius of the corners.
 * @param Number [dx] - The horizontal diameter of the corners.
 * @param Number [dy] - The vertical diameter of the corners.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizeCushion(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[1] * 2),
            divisor(s[2])
        ],
        radius = [
            min(size[0] / 2, c[0]),
            min(size[1] / 2, c[1])
        ]
    )
    [ size, radius[0] && radius[1] ? radius : [0, 0] ]
;

/**
 * Computes the size of a bullet shape.
 *
 * @param Number|Vector [size] - The size of the bullet.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizeBullet(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[0] * 2),
            divisor(s[2] ? s[2] : c[1])
        ],
        horRadius = max(size[0], size[1]) / 2,
        radius = [
            horRadius,
            min(size[2], or(c[1], horRadius))
        ]
    )
    [ size, radius ]
;

/**
 * Computes the size of a pill shape.
 *
 * @param Number|Vector [size] - The size of the pill.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizePill(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[0] * 2),
            divisor(s[2] ? s[2] : c[1] * 2)
        ],
        horRadius = max(size[0], size[1]) / 2,
        radius = [
            horRadius,
            min(size[2] / 2, or(c[1], horRadius))
        ]
    )
    [ size, radius ]
;

/**
 * Computes the size of a peg shape.
 *
 * @param Number|Vector [size] - The size of the peg.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizePeg(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[0] * 2),
            divisor(s[2] ? s[2] : c[1] * 2)
        ],
        radius = [
            min(max(size[0], size[1]) / 2, c[0]),
            min(size[2] / 2, c[1])
        ]
    )
    [ size, radius[0] && radius[1] ? radius : [0, 0] ]
;

/**
 * Computes the size of a plate shape.
 *
 * @param Number|Vector [size] - The size of the plate.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[] - Returns an array containing the size vector and the radius vector.
 */
function sizePlate(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        s = apply3D(size, l, w, h),
        c = sizeRounded2D(r=r, d=d, rx=rx, ry=ry, dx=dx, dy=dy),
        size = [
            divisor(s[0] ? s[0] : c[0] * 2),
            divisor(s[1] ? s[1] : c[0] * 2),
            divisor(s[2] ? s[2] : c[1] * 2)
        ],
        verRadius = size[2] / 2,
        radius = [
            min(max(size[0], size[1]) / 2, or(c[0], verRadius)),
            verRadius
        ]
    )
    [ size, radius ]
;

/**
 * Computes the points that draw the sketch of a bullet shape.
 *
 * @param Number|Vector [size] - The size of the bullet.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[]
 */
function drawBullet(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        specs = sizeBullet(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy),
        size = specs[0],
        radius = specs[1],
        center = [
            0, size[2] - radius[1]
        ],
        points = arc(r=radius, o=center, a=RIGHT)
    )
    complete(points, [radius[0], 0], [0, 0])
;

/**
 * Computes the points that draw the sketch of a pill shape.
 *
 * @param Number|Vector [size] - The size of the pill.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[]
 */
function drawPill(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        specs = sizePill(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy),
        size = specs[0],
        radius = specs[1],
        center = [
            0, size[2] / 2 - radius[1]
        ]
    )
    center == [0, 0] ? arc(r=radius, a1=-RIGHT, a2=RIGHT)
   :concat(
        arc(r=radius, o=-center, a=RIGHT, a1=-RIGHT),
        arc(r=radius, o=center, a=RIGHT)
    )
;

/**
 * Computes the points that draw the sketch of a peg shape.
 *
 * @param Number|Vector [size] - The size of the peg.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[]
 */
function drawPeg(size, r, d, l, w, h, rx, ry, dx, dy) =
    let(
        specs = sizePeg(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy),
        size = specs[0],
        radius = specs[1],
        right = max(size[0], size[1]) / 2,
        top = size[2] / 2,
        center = [
            right - radius[0],
            top - radius[1]
        ]
    )
    radius == [0, 0] ? [ [right, top], [0, top], [0, -top], [right, -top] ]
   :center == [0, 0] ? arc(r=radius, a1=-RIGHT, a2=RIGHT)
   :complete(
        concat(
            arc(r=radius, o=[center[0], -center[1]], a1=QUADRANT_3, a2=QUADRANT_4),
            arc(r=radius, o=center, a1=0, a2=QUADRANT_1)
        ),
        [0, -top],
        [0, top]
    )
;

/**
 * Computes the points that draw the sketch of a plate shape.
 *
 * @param Number|Vector [size] - The size of the plate.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @returns Vector[]
 */
function drawPlate(size, r, d, w, h, rx, ry, dx, dy) =
    let(
        specs = sizePlate(size=size, r=r, d=d, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy),
        size = specs[0],
        radius = specs[1],
        center = [
            max(size[0], size[1]) / 2 - radius[0], 0
        ],
        points = arc(r=radius, o=center, a1=-RIGHT, a2=RIGHT)
    )
    center == [0, 0] ? points
   :complete(points, -[0, radius[1]], [0, radius[1]])
;

/**
 * Creates an arch box at the origin.
 *
 * @param Number|Vector [size] - The size of the arch.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @param Boolean [center] - Whether or not center the box on the vertical axis.
 */
module archBox(size, r, d, l, w, h, rx, ry, dx, dy, center) {
    size = sizeArchBox(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    linear_extrude(height=size[0][2], center=center, convexity=10) {
        arch(size[0], size[1]);
    }
}

/**
 * Creates a slot shape at the origin.
 *
 * @param Number|Vector [size] - The size of the stadium.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 * @param Boolean [center] - Whether or not center the box on the vertical axis.
 */
module slot(size, r, d, l, w, h, rx, ry, dx, dy, center) {
    size = sizeSlot(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    linear_extrude(height=size[0][2], center=center, convexity=10) {
        stadium(size[0], size[1]);
    }
}

/**
 * Creates a cushion shape at the origin.
 *
 * @param Number|Vector [size] - The size of the rounded rectangle.
 * @param Number|Vector [r] - The radius of the corners or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter of the corners  or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius of the corners.
 * @param Number [ry] - The vertical radius of the corners.
 * @param Number [dx] - The horizontal diameter of the corners.
 * @param Number [dy] - The vertical diameter of the corners.
 * @param Boolean [center] - Whether or not center the box on the vertical axis.
 */
module cushion(size, r, d, l, w, h, rx, ry, dx, dy, center) {
    size = sizeCushion(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    linear_extrude(height=size[0][2], center=center, convexity=10) {
        roundedRectangle(size[0], size[1]);
    }
}

/**
 * Creates a bullet shape at the origin.
 *
 * @param Number|Vector [size] - The size of the bullet.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 */
module bullet(size, r, d, l, w, h, rx, ry, dx, dy) {
    specs = sizeBullet(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    resize(specs[0]) {
        rotate_extrude(convexity=10) {
            polygon(
                points=drawBullet(size=specs[0], r=specs[1]),
                convexity=10
            );
        }
    }
}

/**
 * Creates a pill shape at the origin.
 *
 * @param Number|Vector [size] - The size of the pill.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 */
module pill(size, r, d, l, w, h, rx, ry, dx, dy) {
    specs = sizePill(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    resize(specs[0]) {
        rotate_extrude(convexity=10) {
            polygon(
                points=drawPill(size=specs[0], r=specs[1]),
                convexity=10
            );
        }
    }
}

/**
 * Creates a peg shape at the origin.
 *
 * @param Number|Vector [size] - The size of the peg.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 */
module peg(size, r, d, l, w, h, rx, ry, dx, dy) {
    specs = sizePeg(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    resize(specs[0]) {
        rotate_extrude(convexity=10) {
            polygon(
                points=drawPeg(size=specs[0], r=specs[1]),
                convexity=10
            );
        }
    }
}

/**
 * Creates a plate shape at the origin.
 *
 * @param Number|Vector [size] - The size of the plate.
 * @param Number|Vector [r] - The radius or a vector that contains horizontal and vertical radius.
 * @param Number|Vector [d] - The diameter or a vector that contains horizontal and vertical diameters.
 * @param Number [l] - The overall length.
 * @param Number [w] - The overall width.
 * @param Number [h] - The overall height.
 * @param Number [rx] - The horizontal radius.
 * @param Number [ry] - The vertical radius.
 * @param Number [dx] - The horizontal diameter.
 * @param Number [dy] - The vertical diameter.
 */
module plate(size, r, d, l, w, h, rx, ry, dx, dy) {
    specs = sizePlate(size=size, r=r, d=d, l=l, w=w, h=h, rx=rx, ry=ry, dx=dx, dy=dy);
    resize(specs[0]) {
        rotate_extrude(convexity=10) {
            polygon(
                points=drawPlate(size=specs[0], r=specs[1]),
                convexity=10
            );
        }
    }
}

/**
 * Creates a rounded corner wedge at the origin.
 * For now the function can only handle square corner.
 *
 * @param Number [size] - The size of the corner.
 * @param Number [r] - The radius of the round.
 * @param Number [h] - The height of the solid.
 * @param Number [d] - The diameter of the round.
 * @param String|Vector [p] - The position of the corner, as a cardinal point (default: "ne", aka North East).
 * @param Boolean [convex] - Whether makes a convex corner (default: false).
 * @param Number [adjust] - An adjust value added to the size in order to fix wall alignment issue.
 * @param Boolean [center] - Whether or not center the solid on the vertical axis.
 */
module roundedCornerWedge(size, r, h, d, p, convex, adjust, center) {
    linear_extrude(height=divisor(h), center=center, convexity=10) {
        roundedCorner(size=size, r=r, d=d, p=p, convex=convex, adjust=adjust);
    }
}


oblong: switch from using minkowski to offet

minkowski was adding height of the  object.

//
// Common extrusions
// Author: Joseph M. Joy FTC 12598 mentor
//
EPSILON = 0.001; // For moving things to properly punch out holes

// Makes a flat (horizontal) "T":
//
// --------------
// |wtXht     --|
// ----\     /---
//      |wbX|
//      |hb |
//      -----
//<xoff>
//
// It could also be an inverted L shape
// if the lower (vertical) bar is wide enough to extend beyond the right
// hand side of the upper (horizontal) bar.
//
// {xoff} is horizontal distance to the start of the bar.
// {r} is the radius of the
// curve shown as diagonals above.
// t is the thickness of the plate - in
// the z direction.
// Origin is the left hand corner
// of the bounding rectangle.
//
module T_channel(wb, hb, wt, ht, xoff, r, t) {
    ow = 2*wt; // wide enough to
    oh = 2*(hb+ht); // high enough to descend below the shape

    difference() {
        cube([wt, hb+ht, t]);
        translate([xoff-ow,hb-oh,-EPSILON]) oblong(ow, oh, r, t+2*EPSILON);
        translate([xoff+wb,hb-oh,-EPSILON]) oblong(ow, oh, r, t+2*EPSILON);
    }
}

// Makes a flat (horizontal) "O":
//
// /-------------\
// |             |
// | /--------\  |
// | |         | |
// | |         | |
// | |         | |
// | \         / |
// |  ---------  |
// \------------/
//
//
// It could also be a U or L
// if the oblong hole extends outside the outer
// boundary.
//
// ({xoff},{yoff} is origin of bounding-rectangle of the oblong hole
// {(wo}, {ho}) is the bounding box of the outer oblong.
// {(wi}, {hi}) is the bounding box of the inner (hole) oblong.
// {r} is the radius of the
// curve shown as diagonals above.
// t is the thickness of the plate - in
// the z direction.
// Origin is the left hand corner
// of the bounding rectangle.
//
module O_channel(wo, ho, wi, hi, xoff, yoff, r, t) {
    difference() {
        oblong(wo, ho, r, t);
        translate([xoff, yoff, -EPSILON]) oblong(wi, hi, r, t+2*EPSILON);
    }
}

// A rectangular prism that fits within {w} x {h} and
// has rounded corners with radius {r} on all 4 sides.
// The actual radius may be reduced so keep the oblong
// viable. {t} is the thickness (in z).
module oblong2(w, h, r, t) {
    r = min(r, w/2-EPSILON, h/2-EPSILON);
    translate([r, r, 0])
    minkowski() {
        cube([w-2*r, h-2*r, t]);
        cylinder(10, r, r);
    }
}
module oblong(w, h, r, t) {
    r = min(r, w/2-EPSILON, h/2-EPSILON);
    translate([r, r, 0])
    linear_extrude(height = t, center = false, convexity = 10) {
        offset(r = r) square([w-2*r, h-2*r]);
    }
}

//
// Example code
//
wb = 10;
hb = 20;
wt = 40;
ht = 30;
t = 5;
r = 5;
ri = 5;
xoff = 10;
oblong(wb, hb, r, t);
translate([wb+5, 0, 0]) T_channel(wb, hb, wt, ht, xoff, r, t);
translate([wb+wt+10, 0, 0]) O_channel(wt, hb+ht, wb, hb, xoff, xoff, ri, t);

//
// Common extrusions
// Author: Joseph M. Joy FTC 12598 mentor
//
EPSILON = 0.001; // For moving things to properly punch out holes

// Makes a flat (horizontal) "T":
//
// --------------
// |wtXht     --|
// ----\     /---
//      |wbX|
//      |hb |
//      -----
//<xoff>
//
// It could also be an inverted L shape
// if the lower (vertical) bar is wide enough to extend beyond the right
// hand side of the upper (horizontal) bar.
//
// {xoff} is horizontal distance to the start of the bar.
// {r} is the radius of the
// curve shown as diagonals above.
// t is the thickness of the plate - in
// the z direction.
// Origin is the left hand corner
// of the bounding rectangle.
//
module T_channel(wb, hb, wt, ht, xoff, r, t) {
    ow = 10*wb;
    oh = 10*hb;

    difference() {
        cube([wt, hb+ht, t]);
        translate([xoff-ow,hb-oh,-EPSILON]) oblong(ow, oh, r, t+2*EPSILON);
        translate([xoff+wb,hb-oh,-EPSILON]) oblong(ow, oh, r, t+2*EPSILON);
    }
}

// Makes a flat (horizontal) "O":
//
// /-------------\
// |             |
// | /--------\  |
// | |         | |
// | |         | |
// | |         | |
// | \         / |
// |  ---------  |
// \------------/
//
//
// It could also be a U or L
// if the oblong hole extends outside the outer
// boundary.
//
// ({xoff},{yoff} is origin of bounding-rectangle of the oblong hole
// {(wo}, {ho}) is the bounding box of the outer oblong.
// {(wi}, {hi}) is the bounding box of the inner (hole) oblong.
// {r} is the radius of the
// curve shown as diagonals above.
// t is the thickness of the plate - in
// the z direction.
// Origin is the left hand corner
// of the bounding rectangle.
//
module O_channel(wo, ho, wi, hi, xoff, yoff, r, t) {
    difference() {
        oblong(wo, ho, r, t);
        translate([xoff, yoff, -EPSILON]) oblong(wi, hi, r, t+2*EPSILON);
    }
}

// A rectangular prism that fits within {w} x {h} and
// has rounded corners with radius {r} on all 4 sides.
// The actual radius may be reduced so keep the oblong
// viable. {t} is the thickness (in z).
module oblong(w, h, r, t) {
    r = min(r, w/2-EPSILON, h/2-EPSILON);
    translate([r, r, 0])
    minkowski() {
        cube([w-2*r, h-2*r, t]);
        cylinder(2*t, r, r);
    }
}

wb = 5;
hb = 20;
wt = 40;
ht = 30;
t = 2;
r = 5;
ri = 5;
xoff = 10;
//T_channel(wb, hb, wt, ht, xoff, r, t);
O_channel(wt, hb+ht, wb, hb+ht, xoff, xoff, ri, t);
//oblong(11, 40, 5, 2);


The whitespce in the code was formatted.  The knurled surface library is now included from the external-resources directory, via a 'use' statement.

/**
 * This script renders onebeartoe Fidget Spinners!
 *
 * Author: Roberto Marquez
 *
 * https://plus.google.com/u/0/104101484714566033177
 * https://twitter.com/onebeartoe
 * https://www.youtube.com/user/onebeartoe/videos
 *
 *  Originally from: http://www.thingiverse.com/thing:1937473
 *  Original Author: Geoff Buttsworth
 *  Original Filename: moneySpinner02
 *  Borrowed from Version: 0.5
 *  Twitter: @gbutts9
 *
 *  This version is designed to work with the Thingiverse Customizer.
 *  Ref: http://customizer.makerbot.com/docs
 */

use <../../external-resources\knurled-surface\aubenc\knurledFinishLib_v2.scad>

use <../../shapes\star\star.scad>;

/* [Spinner_Parameters] */
//Which coin do you want to use?
coin_list = 8; //[1:AU $2,2:AU 5c,3:US 10c,4:UK £1,5:UK 5p,6:EU €1,7:QA 0.5QAR,8:US 5c]
coin = coin_list;

//How many spokes should the spinner have?
Number_of_Spokes = 5; //[2,3,4,5,6,7]
spokeNumber = Number_of_Spokes;

//Flush for easier printing
Flush_or_Raised_Hub = 1; //[0:Hub,1:Flush]
flush = Flush_or_Raised_Hub; //Flush is easier to print, the hub is height of bearing and may print with support

//Allocate coin data

coinName = coin == 1 ? "AU $2" :
        (coin == 2 ? "AU 5c" :
        (coin == 3 ? "US 10c" :
        (coin == 4 ? "UK £1" :
        (coin == 5 ? "UK 5p" :
        (coin == 6 ? "EU €1" :
        (coin == 7 ? "QA 0.5QAR" : "US 5c")
        )
        )
        )
        )
        );

coin_d = coin == 1 ? 20.5 :
        (coin == 2 ? 19.4 :
        (coin == 3 ? 17.9 :
        (coin == 4 ? 22.5 :
        (coin == 5 ? 18.0 :
        (coin == 6 ? 23.3 :
        (coin == 7 ? 25.0 : 21.3)
        )
        )
        )
        )
        );

coin_z = coin == 1 ? 2.8 :
        (coin == 2 ? 1.3 :
        (coin == 3 ? 1.35 :
        (coin == 4 ? 3.15 :
        (coin == 5 ? 1.8 :
        (coin == 6 ? 2.35 :
        (coin == 7 ? 1.78 : 1.95)
        )
        )
        )
        )
        );

stack = coin == 2 ? 3 :
        (coin == 3 ? 3 :
        (coin == 5 ? 3 :
        (coin == 7 ? 3 :
        (coin == 8 ? 4 : 2)
        )
        )
        );

//Default values
$fa = 0.8;
$fs = 0.8;

//Variables:

rim = 5;
holder_d = coin_d + rim;
holder_z = coin_z*stack;

brg_d = 22.0;
brg_z = 7.0;

spoke_x = coin_d / 2;
spoke_y = coin_d / 3;
spoke_z = holder_z;

//If flush: hub will be height of coin stack otherwise height of bearing
hub_z = flush == 1 ? coin_z*stack : brg_z;

//SpinnerModules

module dollarHolder() {

    translate([0, coin_d / 2 + spoke_y, 0])
    difference() {
        translate([0, 0, -coin_z * stack / 2])
        knurl(k_cyl_hg = holder_z, k_cyl_od = holder_d);

        xyScale = 0.75;
        translate([0, 0, -5])
        scale([xyScale, xyScale, 1])
        starThumbnail(height = 10);
        //			cylinder(d=coin_d,h=holder_z+4,center=true);
    }
}

module hub() {
    cylinder(h = hub_z, d = brg_d + rim, center = true);
}

module spoke() {
    translate([0, spoke_y / 2, 0])
    cube([spoke_x, spoke_y, spoke_z], center = true);
}

module brgVoid() {
    cylinder(h = brg_z + 2, d = brg_d, center = true);
}

module holderSpoke() {

    translate([0, brg_d / 2, 0])
            union() {
        dollarHolder();
        spoke();
    }
}

//Rotate
rA = 360 / spokeNumber; //rotational angle
fA = round(360 - rA); //final angle

module spinner() {
    for (i = [0 : rA : fA]) {
        rotate([0, 0, i])
        holderSpoke();
    }
}

//Finalise

module plus() {
    hub();
    spinner();
}

module minus() {
    brgVoid();
}

//Render

difference() {
    plus();
    minus();
}

/**
    Originally from: http://www.thingiverse.com/thing:1937473
    Original Author: Geoff Buttsworth
    Original Filename: moneySpinner02
    Borrowed from Version: 0.5
    Twitter: @gbutts9

    This version is designed to work with the Thingiverse Customizer.
    Ref: http://customizer.makerbot.com/docs
*/

/*
    The knurled library is incorporated in toto here as Customizer is limited to one SCAD file.

	 * knurledFinishLib_v2.scad
	 *
	 * Written by aubenc @ Thingiverse
	 *
	 * This script is licensed under the Public Domain license.
	 *
	 * http://www.thingiverse.com/thing:31122
	 *
	 * Derived from knurledFinishLib.scad (also Public Domain license) available at
	 *
	 * http://www.thingiverse.com/thing:9095
	 *
*/

use <../../shapes\star\star.scad>;

/* [Spinner_Parameters] */
//Which coin do you want to use?
coin_list=8;//[1:AU $2,2:AU 5c,3:US 10c,4:UK £1,5:UK 5p,6:EU €1,7:QA 0.5QAR,8:US 5c]
coin=coin_list;

//How many spokes should the spinner have?
Number_of_Spokes=5;//[2,3,4,5,6,7]
spokeNumber=Number_of_Spokes;

//Flush for easier printing
Flush_or_Raised_Hub=1;//[0:Hub,1:Flush]
flush=Flush_or_Raised_Hub;		//Flush is easier to print, the hub is height of bearing and may print with support

//knurledFinishLib_v2
	/*
	 * Usage:
	 *
	 *	 Drop this script somewhere where OpenSCAD can find it (your current project's
	 *	 working directory/folder or your OpenSCAD libraries directory/folder).
	 *
	 *	 Add the line:
	 *
	 *		use <knurledFinishLib_v2.scad>
	 *
	 *	 in your OpenSCAD script and call either...
	 *
	 *    knurled_cyl( Knurled cylinder height,
	 *                 Knurled cylinder outer diameter,
	 *                 Knurl polyhedron width,
	 *                 Knurl polyhedron height,
	 *                 Knurl polyhedron depth,
	 *                 Cylinder ends smoothed height,
	 *                 Knurled surface smoothing amount );
	 *
	 *  ...or...
	 *
	 *    knurl();
	 *
	 *	If you use knurled_cyl() module, you need to specify the values for all and
	 *
	 *  Call the module ' help(); ' for a little bit more of detail
	 *  and/or take a look to the PDF available at http://www.thingiverse.com/thing:9095
	 *  for a in depth descrition of the knurl properties.
	 */

	module knurl(	k_cyl_hg	= 12,
						k_cyl_od	= 25,
						knurl_wd =  3,
						knurl_hg =  4,
						knurl_dp =  1.5,
						e_smooth =  2,
						s_smooth =  0)
	{
	    knurled_cyl(k_cyl_hg, k_cyl_od,
	                knurl_wd, knurl_hg, knurl_dp,
	                e_smooth, s_smooth);
	}

	module knurled_cyl(chg, cod, cwd, csh, cdp, fsh, smt)
	{
	    cord=(cod+cdp+cdp*smt/100)/2;
	    cird=cord-cdp;
	    cfn=round(2*cird*PI/cwd);
	    clf=360/cfn;
	    crn=ceil(chg/csh);

	    echo("knurled cylinder max diameter: ", 2*cord);
	    echo("knurled cylinder min diameter: ", 2*cird);

		 if( fsh < 0 )
	    {
	        union()
	        {
	            shape(fsh, cird+cdp*smt/100, cord, cfn*4, chg);

	            translate([0,0,-(crn*csh-chg)/2])
	              knurled_finish(cord, cird, clf, csh, cfn, crn);
	        }
	    }
	    else if ( fsh == 0 )
	    {
	        intersection()
	        {
	            cylinder(h=chg, r=cord-cdp*smt/100, $fn=2*cfn, center=false);

	            translate([0,0,-(crn*csh-chg)/2])
	              knurled_finish(cord, cird, clf, csh, cfn, crn);
	        }
	    }
	    else
	    {
	        intersection()
	        {
	            shape(fsh, cird, cord-cdp*smt/100, cfn*4, chg);

	            translate([0,0,-(crn*csh-chg)/2])
	              knurled_finish(cord, cird, clf, csh, cfn, crn);
	        }
	    }
	}

	module shape(hsh, ird, ord, fn4, hg)
	{
		x0= 0;	x1 = hsh > 0 ? ird : ord;		x2 = hsh > 0 ? ord : ird;
		y0=-0.1;	y1=0;	y2=abs(hsh);	y3=hg-abs(hsh);	y4=hg;	y5=hg+0.1;

		if ( hsh >= 0 )
		{
			rotate_extrude(convexity=10, $fn=fn4)
			polygon(points=[	[x0,y1],[x1,y1],[x2,y2],[x2,y3],[x1,y4],[x0,y4]	],
						paths=[	[0,1,2,3,4,5]	]);
		}
		else
		{
			rotate_extrude(convexity=10, $fn=fn4)
			polygon(points=[	[x0,y0],[x1,y0],[x1,y1],[x2,y2],
									[x2,y3],[x1,y4],[x1,y5],[x0,y5]	],
						paths=[	[0,1,2,3,4,5,6,7]	]);
		}
	}

	module knurled_finish(ord, ird, lf, sh, fn, rn)
	{
	    for(j=[0:rn-1])
	    assign(h0=sh*j, h1=sh*(j+1/2), h2=sh*(j+1))
	    {
	        for(i=[0:fn-1])
	        assign(lf0=lf*i, lf1=lf*(i+1/2), lf2=lf*(i+1))
	        {
	            polyhedron(
	                points=[
	                     [ 0,0,h0],
	                     [ ord*cos(lf0), ord*sin(lf0), h0],
	                     [ ird*cos(lf1), ird*sin(lf1), h0],
	                     [ ord*cos(lf2), ord*sin(lf2), h0],

	                     [ ird*cos(lf0), ird*sin(lf0), h1],
	                     [ ord*cos(lf1), ord*sin(lf1), h1],
	                     [ ird*cos(lf2), ird*sin(lf2), h1],

	                     [ 0,0,h2],
	                     [ ord*cos(lf0), ord*sin(lf0), h2],
	                     [ ird*cos(lf1), ird*sin(lf1), h2],
	                     [ ord*cos(lf2), ord*sin(lf2), h2]
	                    ],
	                triangles=[
	                     [0,1,2],[2,3,0],
	                     [1,0,4],[4,0,7],[7,8,4],
	                     [8,7,9],[10,9,7],
	                     [10,7,6],[6,7,0],[3,6,0],
	                     [2,1,4],[3,2,6],[10,6,9],[8,9,4],
	                     [4,5,2],[2,5,6],[6,5,9],[9,5,4]
	                    ],
	                convexity=5);
	         }
	    }
	}

	module knurl_help()
	{
		echo();
		echo("    Knurled Surface Library  v2  ");
	   echo("");
		echo("      Modules:    ");
		echo("");
		echo("        knurled_cyl(parameters... );    -    Requires a value for each an every expected parameter (see bellow)    ");
		echo("");
		echo("        knurl();    -    Call to the previous module with a set of default parameters,    ");
		echo("                                  values may be changed by adding 'parameter_name=value'        i.e.     knurl(s_smooth=40);    ");
		echo("");
		echo("      Parameters, all of them in mm but the last one.    ");
		echo("");
		echo("        k_cyl_hg       -   [ 12   ]  ,,  Height for the knurled cylinder    ");
		echo("        k_cyl_od      -   [ 25   ]  ,,  Cylinder's Outer Diameter before applying the knurled surfacefinishing.    ");
		echo("        knurl_wd     -   [   3   ]  ,,  Knurl's Width.    ");
		echo("        knurl_hg      -   [   4   ]  ,,  Knurl's Height.    ");
		echo("        knurl_dp     -   [  1.5 ]  ,,  Knurl's Depth.    ");
		echo("        e_smooth   -    [  2   ]  ,,  Bevel's Height at the bottom and the top of the cylinder    ");
		echo("        s_smooth   -    [  0   ]  ,,  Knurl's Surface Smoothing :  File donwn the top of the knurl this value, i.e. 40 will snooth it a 40%.    ");
		echo("");
	}

//Allocate coin data

	coinName=coin==1 ? "AU $2" :
		(coin==2 ? "AU 5c" :
			(coin==3 ? "US 10c" :
				(coin==4 ? "UK £1" :
					(coin==5 ? "UK 5p" :
						(coin==6 ? "EU €1" :
							(coin==7 ? "QA 0.5QAR" : "US 5c")
						)
					)
				)
			)
		);

	coin_d=coin==1 ? 20.5 :
		(coin==2 ? 19.4 :
			(coin==3 ? 17.9 :
				(coin==4 ? 22.5 :
					(coin==5 ? 18.0 :
						(coin==6 ? 23.3 :
							(coin==7 ? 25.0 : 21.3)
						)
					)
				)
			)
		);

	coin_z=coin==1 ? 2.8 :
		(coin==2 ? 1.3 :
			(coin==3 ? 1.35 :
				(coin==4 ? 3.15 :
					(coin==5 ? 1.8 :
						(coin==6 ? 2.35 :
							(coin==7 ? 1.78 : 1.95)
						)
					)
				)
			)
		);

	stack=coin==2 ? 3 :
		(coin==3 ? 3 :
			(coin==5 ? 3 :
				(coin==7 ? 3 :
					(coin==8 ? 4 : 2)
				)
			)
		);

//Default values
	$fa=0.8;
	$fs=0.8;

//Variables:

	rim=5;
	holder_d=coin_d+rim;
	holder_z=coin_z*stack;

	brg_d=22.0;
	brg_z=7.0;

	spoke_x=coin_d/2;
	spoke_y=coin_d/3;
	spoke_z=holder_z;

	//If flush: hub will be height of coin stack otherwise height of bearing
	hub_z=flush==1 ? coin_z*stack : brg_z;

//SpinnerModules

	module dollarHolder() {
		translate([0,coin_d/2+spoke_y,0])
		difference() {
			translate([0,0,-coin_z*stack/2])
				knurl(k_cyl_hg=holder_z,k_cyl_od=holder_d);

			xyScale = 0.75;
			translate([0, 0, -5])
			scale([xyScale, xyScale, 1])
			starThumbnail(height=10);
//			cylinder(d=coin_d,h=holder_z+4,center=true);
		}
	}

	module hub() {
			cylinder(h=hub_z,d=brg_d+rim,center=true);
	}

	module spoke() {
		translate([0,spoke_y/2,0])
			cube([spoke_x,spoke_y,spoke_z], center=true);
	}

	module brgVoid() {
		cylinder(h=brg_z+2,d=brg_d,center=true);
	}

	module holderSpoke() {
		translate([0,brg_d/2,0])
		union() {
			dollarHolder();
			spoke();
		}
	}

//Rotate
	rA = 360/spokeNumber;	//rotational angle
	fA = round(360-rA);		//final angle

	module spinner() {
		for (i = [0:rA:fA]) {
			rotate([0,0,i])
				holderSpoke();
		}
	}

//Finalise
	module plus() {
		hub();
		spinner();
	}

	module minus() {
		brgVoid();
	}

	//Render
	difference() {
		plus();
		minus();
	}


The left over near the left head left colar bone was removed.

headCutoutRadius = 19;

module headRemover()
{
    difference()
    {
        cubeLengthX = 95;
        cube([cubeLengthX, 85, 70]);

        translate([40, 120, -3])
        rotate([90, 0, 0])
        cylinder(r=headCutoutRadius,
                 h=129,
                 $fn=60);
    }
}

module headlessTroll(stlPath, cutHeight)
{
    trollY = 140;
    difference()
    {
        translate([0, trollY, 0])
        originalTroll(stlPath);

        color("green")
        translate([-17, 132, 58.5])
        headRemover();

        // remove the left overs

//    }

		color("orange")
		translate([21, 172, 74])
		rotate([0,20,0])
		cube([15, 30, 5]);
	}
}

// Jesse Troll?
module originalTroll(stlPath)
{
    translate([-20,-40,0])
    import(stlPath);
}

/**
 * unionDifference: true gets union, false gets difference
 */
module trollHead(stlPath)
{
    difference()
    {
        intersection()
        {
            translate([0, 260, 0])
            originalTroll(stlPath);

            translate([22.5, 295, 133.7])
            sphere(r=70.4);
        }

        translate([23, 272, 54])
        sphere(r=20);

        translate([23, 310, 54])
        sphere(r=20);

        color("green")
        translate([23, 280, 48])
        cube([20,25,20]);

        color("blue")

        translate([23, 277, 51.5])
        rotate([-9, 0, 0])
        cube([20,25,20]);
    }
}

module twoHeadedTroll(stlPath)
{
    union()
    {
        s = 0.7;
        headScale = [s, s, s];
        headRotate = 9.8;

        headX = 10;
        rightHeadY = 285;
        headZ = 22;

        // left head
        color("yellow")
        translate([headX, rightHeadY + 40, headZ+30])
        scale(headScale)
        rotate([-headRotate,-10,0])
        trollHead(stlPath);

        // right head
        color("red")
        translate([headX, rightHeadY+20, headZ-33])
        scale(headScale)
        rotate([headRotate, -0, 0])
        trollHead(stlPath);

        twoHeadedTranslateY = 340;

        // neck part
        neckY = twoHeadedTranslateY + 183.5;
        neckRadius = headCutoutRadius - 9;
        translate([22, neckY-9, 68])
//        translate([23, neckY, 68])
        rotate([90,0,0])
//        cylinder(r=neckRadius,
//                 h=22,
//                 $fn=60);
        sphere(r=neckRadius + 7,
               $fn=80);

        // body
        // two headed troll
        twoHeadedTranslate = [0, twoHeadedTranslateY, 0];
        color("pink")
        translate(twoHeadedTranslate)
        headlessTroll(stlPath);
    }
}

headCutoutRadius = 19;

module headlessTroll(stlPath, cutHeight)
{
    trollY = 140;
    difference()
    {
        translate([0, trollY, 0])
        originalTroll(stlPath);

        color("green")
        translate([-17, 132, 58.5])
        headRemover();
    }
}

module headRemover()
{
    difference()
    {
        cubeLengthX = 95;
        cube([cubeLengthX, 85, 70]);

        translate([40, 120, -3])
        rotate([90, 0, 0])
        cylinder(r=headCutoutRadius,
                 h=129,
                 $fn=60);
    }
}

// Jesse Troll?
module originalTroll(stlPath)
{
    translate([-20,-40,0])
    import(stlPath);
}

/**
 * unionDifference: true gets union, false gets difference
 */
module trollHead(stlPath)
{
    difference()
    {
        intersection()
        {
            translate([0, 260, 0])
            originalTroll(stlPath);

            translate([22.5, 295, 133.7])
            sphere(r=70.4);
        }

        translate([23, 272, 54])
        sphere(r=20);

        translate([23, 310, 54])
        sphere(r=20);

        color("green")
        translate([23, 280, 48])
        cube([20,25,20]);

        color("blue")

        translate([23, 277, 51.5])
        rotate([-9, 0, 0])
        cube([20,25,20]);
    }
}

module twoHeadedTroll(stlPath)
{
    union()
    {
        s = 0.7;
        headScale = [s, s, s];
        headRotate = 9.8;

        headX = 10;
        rightHeadY = 285;
        headZ = 22;

        // left head
        color("yellow")
        translate([headX, rightHeadY + 40, headZ+30])
        scale(headScale)
        rotate([-headRotate,-10,0])
        trollHead(stlPath);

        // right head
        color("red")
        translate([headX, rightHeadY+20, headZ-33])
        scale(headScale)
        rotate([headRotate, -0, 0])
        trollHead(stlPath);

        twoHeadedTranslateY = 340;

        // neck part
        neckY = twoHeadedTranslateY + 183.5;
        neckRadius = headCutoutRadius - 9;
        translate([22, neckY-9, 68])
//        translate([23, neckY, 68])
        rotate([90,0,0])
//        cylinder(r=neckRadius,
//                 h=22,
//                 $fn=60);
        sphere(r=neckRadius + 7,
               $fn=80);

        // body
        // two headed troll
        twoHeadedTranslate = [0, twoHeadedTranslateY, 0];
        color("pink")
        translate(twoHeadedTranslate)
        headlessTroll(stlPath);
    }
}


added one more support element, for a print to look better

holderDiameter = 25 + 2*1.5;
cubeLen = 7+8/2 + 2.5 + holderDiameter/2;

difference()
{
  union()
  {
    // mounting rod
    cube([7, 8, 20]);
    translate([7, 8/2, 0])
      cylinder(r=8/2, h=20, $fs=0.1);

    // connecting bar
    translate([0, 0, 20])
      cube([cubeLen, 8, 4]);
    translate([cubeLen-holderDiameter/2, -holderDiameter/2+8, 0])
      cube([holderDiameter/2, holderDiameter/2, 20+4]);

    // marker holder - main part
    translate([cubeLen, -holderDiameter/2+8, 0])
      cylinder(r=(holderDiameter)/2, h=50);
  }
  // marker holder drill
  translate([cubeLen, -holderDiameter/2+8, 0])
    translate([0, 0, 1.5])
      cylinder(r=25/2, h=50);
}

holderDiameter = 25 + 2*1.5;
cubeLen = 7+8/2 + 0 + holderDiameter/2;

difference()
{
  union()
  {
    // mounting rod
    cube([7,8,20]);
    translate([7,8/2,0])
      cylinder(r=8/2, h=20, $fs=0.1);

    // connecting bar
    translate([0, 0, 20])
      cube([cubeLen, 8, 4]);

    // marker holder - main part
    translate([cubeLen, -holderDiameter/2+8, 0])
      cylinder(r=(holderDiameter)/2, h=50);
  }
  // marker holder drill
  translate([cubeLen, -holderDiameter/2+8, 0])
    translate([0, 0, 1.5])
      cylinder(r=25/2, h=50);
}


shapes/rcylindera: fix rounding always disabled

include <system.scad>
include <units.scad>
use <misc.scad>
use <transforms.scad>

module cubea(size=[10,10,10], align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0], orient=[0,0,1], roll=0, extra_roll, extra_roll_orient)
{
    size_align(size=size,extra_size=extrasize, align=align, extra_align=extrasize_align, orient=orient, orient_ref=[0,0,1], roll=roll, , extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    {
        cube(size+extrasize, center=true);
    }
}

module rcubea(size=[10,10,10], rounding_radius=1, align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0], orient=[0,0,1], roll=0, extra_roll, extra_roll_orient)
{
    size_align(size=size,extra_size=extrasize, align=align, extra_align=extrasize_align, orient=orient, orient_ref=[0,0,1], roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    {
        rcube(size=size+extrasize, rounding_radius=rounding_radius);
    }
}

/*cubea(size=[10,20,30], align=[0,-1,0], orient=[0,0,1], roll=10, extra_roll=-30, extra_roll_orient=[1,0,0]);*/

module rcube(size=[20,20,20], rounding_radius=1)
{
    if($preview_mode || rounding_radius == 0)
    {
        cubea(size);
    }
    else
    {
        hull()
        for(x=[-(size[0]/2-rounding_radius),(size[0]/2-rounding_radius)])
        for(y=[-(size[1]/2-rounding_radius),(size[1]/2-rounding_radius)])
        for(z=[-(size[2]/2-rounding_radius),(size[2]/2-rounding_radius)])
        translate([x,y,z])
        sphere(r=rounding_radius);
    }
}

module cylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        orient=[0,0,1],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,0],
        round_radius=0,
        debug=false
        )
{
    pi=3.1415926536;

    d1_ = v_fallback(d1, [r*2, r1*2]);
    d2_ = v_fallback(d2, [r*2, r2*2]);

    r1_ = v_fallback(r1, [d1_/2, d/2, r]);
    r2_ = v_fallback(r2, [d2_/2, d/2, r]);

    r_max = v_fallback(r, [max(r1_,r2_)]);

    extra_r_ = v_fallback(extra_r, [0]);

    if(debug)
    {
        echo(useDia, h, r_, r1_, r2_, extra_r_, align);
    }

    size_align(size=[r_max*2,r_max*2,h], extra_size=[extra_r_*2, extra_r_*2, extra_h], orient=orient, orient_ref=[0,0,1], align=align, extra_align=extra_align)
    {
        if(round_radius>0)
        {
            rcylindera(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, round_radius=round_radius);
        }
        else
        {
            cylinder(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, center=true);
        }
    }
}

/*translate([10,0,0])*/
/*rotate_extrude()*/
        /*translate([10-2,2,0])*/
/*$fa = 5.6;*/
/*$fs = 0.3;*/
/*circle(r = 100);*/
/*torus(10, 2, align=[0,0,0], orient=[0,0,1]);*/

module torus(radius, radial_width, align=[0,0,0], orient=[0,0,1])
{
    size_align(size=[radius*2+radial_width*2, radius*2+radial_width*2, radial_width*2], align=align, orient=orient)
    rotate_extrude()
    translate([radius, 0, 0])
    circle(radial_width);
}

module rcylindera(d, d1, d2, r, r1, r2, h=10, round_radius=2, align=[0,0,0], orient=[0,0,1])
{
    if($preview_mode || round_radius == 0)
    {
        cylindera(d=d, d1=d1, d2=d2, r=r, r1=r1, r2=r2, h=h, align=align, orient=orient);
    }
    else
    {
        d1_ = v_fallback(d1, [r*2, r1*2]);
        d2_ = v_fallback(d2, [r*2, r2*2]);

        r1_ = v_fallback(r1, [d/2, d1_/2]);
        r2_ = v_fallback(r2, [d/2, d2_/2]);

        r_ = [r1_,r2_];

        size_align(align=align, orient=orient)
        hull()
        {
            for(z=[-1,1])
            translate([0, 0, z*(-h/2)])
            {
                r__=z!=-1?r_[0]:r_[1];
                torus(radius=r__-round_radius/2, radial_width=round_radius/2, align=[0,0,z]);
            }
        }
    }
}

// positive angles go from start to end counterclockwise
// negative angles are allowed
module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    intersection() {
        circle(r);
        polygon([
                [0,0],
                [R * cos(a0), R * sin(a0)],
                [R * cos(a1), R * sin(a1)],
                [R * cos(a2), R * sin(a2)],
                [R * cos(a3), R * sin(a3)],
                [R * cos(a4), R * sin(a4)],
                [0,0]
        ]);
    }
}

// positive angles go from start to end counterclockwise
// negative angles are allowed
module pie_slice(r, start_angle, end_angle, h, orient=[0,0,1], align=[0,0,0])
{
    size_align(size=[r*2, r*2, h], orient=orient, orient_ref=[0,0,1], align=align)
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

module hollow_cylinder(d=10, thickness=1, h=10, taper=false, taper_h=undef, orient=[0,0,1], align=[0,0,0])
{
    outer_d = d+thickness/2;
    inner_d = d-thickness/2;
    taper_h = taper_h == undef ? min(h/4, (outer_d-inner_d)/2) : max(taper_h,h/2);
    taper_ = taper && taper_h > 0;
    size_align(size=[outer_d, outer_d, h], orient=orient, align=align);
    difference()
    {
        union()
        {
            cylindera(h=h-(taper_?taper_h*2:0), d=outer_d, orient=[0,0,1], align=[0,0,0]);
            if(taper_)
            {
                for(z=[-1,1])
                translate([0,0,z*(h/2-taper_h)])
                mirror([0,0,z==-1?1:0])
                cylindera(d1=outer_d, d2=outer_d-inner_d/4, h=taper_h, align=[0,0,1]);
            }
        }
        if(taper_)
        {
            for(z=[-1,1])
            translate([0,0,z*(h/2-taper_h)])
            mirror([0,0,z==-1?1:0])
            cylindera(d1=inner_d, d2=outer_d, h=taper_h+.1, align=[0,0,1]);

            // override fn for inner cylinder cut, to ensure same fragments as taper
            // this ensures cleaner mesh
            fn = fn_from_d(d=outer_d);
            cylindera(h=h+.2+taper_h, d=inner_d, orient=[0,0,1], align=[0,0,0], $fn=fn);
        }
        else
        {
            cylindera(h=h+.2, d=inner_d, orient=[0,0,1], align=[0,0,0]);
        }
    }
}

/**
 * Standard right-angled triangle
 *
 * @param number o_len Lenght of the opposite side
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 * @todo a better way ?
 */
module triangle(o_len, a_len, depth, align=[0,0,0], orient=[0,0,1])
{
    size_align(size=[a_len, depth, o_len], align=align, orient=orient)
    rotate([90,0,0])
    translate([-a_len/2, -o_len/2, -depth/2])
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,o_len]], paths=[[0,1,2]]);
    }
}

/**
 * Rounded Standard right-angled triangle
 *
 * @param number o_len Lenght of the opposite side
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 * @todo a better way ?
 */
module rtriangle(o_len, a_len, depth, rounding_radius=2, align=[0,0,0], orient=[0,0,1])
{
    size = [a_len-rounding_radius, depth-rounding_radius, o_len-rounding_radius];
    r_x = rounding_radius;
    r_y = rounding_radius;
    r_z = -rounding_radius;

    hyp = pythag_hyp(o_len,a_len);
    a_z = atan(a_len/o_len);

    translate([0,0,size[2]+2])
    color([1,0,0])
    rotate([90,90,0])
    pie_slice(r=2, start_angle=0, end_angle=a_z, h=depth);

    /*translate([size[0]+4,0,0])*/
    /*color([1,0,0])*/
    /*rotate([90,90,0])*/
    /*pie_slice(r=2, start_angle=90, end_angle=90+a_z, h=depth);*/

    size_align(size=size, align=align, orient=orient)
    /*hull()*/
    for(x=[-(size[0]/2)+rounding_radius,(size[0]/2)-r_x])
    for(y=[-(size[1]/2)+rounding_radius,(size[1]/2)-r_y])
    for(z=[-(size[2]/2)+rounding_radius,(size[2]/2)-r_z])
    translate([x,y,z])
    if(x<=1 || z<=1)
    sphere(r=rounding_radius);
}

module teardrop(r, d, h=10, truncate=1, align=[0,0,0], orient=[0,1,0], roll=0)
{
    r_= v_fallback(r, [d/2]);

    sx1 = r_ * sin(-45);
    sx2 = r_ * -sin(-45);
    sy = r_ * -cos(-45);
    ex = 0;
    ey = (sin(-135) + cos(-135)) * r_;

    dx= ex-sx1;
    dy = ey-sy;

    eys = lerp(-r_,ey,1-truncate);

    dys = eys-sy;
    ex1 = sy+dys*dx/dy;
    ex2 = -ex1;

    size_align(size=[d,d,h], align=align, orient=orient, orient_ref=[0,0,1], roll=roll)
    union()
    {
        linear_extrude(height = h, center = true, convexity = r_, twist = 0)
        circle(r = r_, center = true);

        linear_extrude(height = h, center = true, convexity = r_, twist = 0)
        polygon(points = [
                [sy, sx1],
                [sy, sx2],
                [eys, ex2],
                [eys, ex1]],
                paths = [[0, 1, 2, 3]]);
    }
}

// test teardrop
if(false)
{
    r=5*mm;
    for(axis=concat(AXES,-AXES))
    translate(axis*r*2)
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        teardrop(r=r, h=20, orient=axis, align=axis);
    }
}

// test cubea
if(false)
{
    w=5*mm;
    h=2*mm;
    for(axis=concat(AXES,-AXES))
    /*translate(axis)*/
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        cubea([w,w,h], orient=axis, align=axis*3);
    }
}
/**
/*debug();*/

module debug()
{
    $fs = 0.1;
    $fa = 1;

    /*triangle_a(45, 5, 5);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=[0,0,-1]);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=[0,0,1]);*/

    triangle(10, 30, 5, align=[1,1,1], orient=[0,0,1]);
    translate([0,-10,0])
    rtriangle(10, 30, 5, align=[1,1,1], orient=[0,0,1]);
}

/**
 * Standard right-angled triangle (tangent version)
 *
 * @param number angle of adjacent to hypotenuse (ie tangent)
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 */
module triangle_a(tan_angle, a_len, depth)
{
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,tan(tan_angle) * a_len]], paths=[[0,1,2]]);
    }
}

// Tests:
module test_triangles()
{
    // Generate a bunch of triangles by sizes
    for (i = [1:10])
    {
        translate([i*7, -30, i*7])
        {
            triangle(i*5, sqrt(i*5+pow(i,2)), 5);
        }
    }

    // Generate a bunch of triangles by angle
    for (i = [1:85/5])
    {
        translate([i*7, 22, i*7])
        {
            triangle_a(i*5, 10, 5);
        }
    }
}

if(false)
{
    stack(axis=XAXIS, dist=15)
    {
        hollow_cylinder(thickness=5, h=10, taper=false, orient=[0,0,1], align=[0,0,1]);
        hollow_cylinder(thickness=5, h=10, taper=true, orient=[0,0,1], align=[0,0,1]);
    }

    /*cylindera(d=10, h=10, orient=[0,0,1], align=[0,0,1]);*/
    /*translate([10,0,0])*/
    /*{*/
    /*hollow_cylinder(d=10, thickness=4, h=10, taper=true, taper_h=.5, orient=[0,0,1], align=[0,0,1]);*/
    /*cylindera(d=8, h=10, orient=[0,0,1], align=[0,0,1]);*/
    /*}*/

    /*%pie_slice(r=10, start_angle=-30, end_angle=270, h=10);*/

    /*cubea([10,10,10],[1,0,0]);*/
    /*%cubea([10,10,10],[1,0,0],[5,5,5],[1,1,1]);*/

    /*%cubea([10,10,10],[-1,0,1]);*/
    /*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
    /*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
    /*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
    /*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=[1,0,0], extra_d=10);*/

    /*hull_pairwise()*/
    /*sphere(30/2);*/

    /*translate([30,0,0])*/
    /*rcubea(s=[35,35,35], rounding_radius=10);*/
    /*rcubea(s=[35,35,35], align=[0,-1,0]);*/

    /*translate([60,0,0])*/
    /*sphere(30/2);*/

    cylindera(h=20, r=5*mm, align=[0,1,0], orient=[0,0,1], $fn=100);

/*size_align(size=[5,5,20], orient=[0,1,0], orient_ref=[0,0,1])*/
/*size_align(size=[5,5,20], orient=[0,1,0], orient_ref=[0,1,0], align=[0,1,0])*/
/*size_align(size=[5,20,5], orient=[0,0,1], orient_ref=[0,1,0], align=[0,0,0])*/
/*rotate([90,0,0])*/
/*cylinder(d=5, h=20, center=true);*/

/*cylindera(d=10, h=10, orient=[0,1,0], align=[0,0,1]);*/
}

if(false)
{
    r=5*mm;
    for(axis=concat(AXES,-AXES))
    translate(axis*r*2)
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        /*cylindera(h=20, r=r, align=axis, orient=axis, extra_h=r, extra_align=-axis, $fn=100);*/
        cylindera(h=20, r1=r, r2=r/2, align=axis, orient=axis, extra_h=r, extra_align=-axis, $fn=16, round_radius=2);
    }
}

if(false)
{
    stack(dist=50, axis=[0,1,0])
    {
        stack(dist=10, axis=[0,0,-1])
        {
            /*cylindera(orient=[0,0,-1], align=[0,0,-1]);*/
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=[0,0,1], align=[0,0,-1]);
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=[0,0,-1], align=[0,0,1]);
            /*pie_slice(r=30, h=5, start_angle=-90, end_angle=180, align=[0,0,-1]);*/
            /*pie_slice(r=30, h=5, start_angle=90, end_angle=270, align=[0,0,-1]);*/
            /*pie_slice(r=30, h=5, start_angle=0, end_angle=270, align=[0,0,-1]);*/
        }

        stack(dist=10, axis=[0,1,0])
        {
            /*cylindera(orient=[0,1,0], align=[0,1,0]);*/
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=[0,-1,0], align=[0,1,0]);
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=[0,1,0], align=[0,1,0]);
            pie_slice(r=30, h=5, start_angle=-90, end_angle=180, orient=[0,1,0], align=[0,1,0]);
            pie_slice(r=30, h=5, start_angle=90, end_angle=270, orient=[0,1,0], align=[0,1,0]);
            pie_slice(r=30, h=5, start_angle=0, end_angle=270, orient=[0,1,0], align=[0,1,0]);
        }
    }
}

include <system.scad>
include <units.scad>
use <misc.scad>
use <transforms.scad>

module cubea(size=[10,10,10], align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0], orient=[0,0,1], roll=0, extra_roll, extra_roll_orient)
{
    size_align(size=size,extra_size=extrasize, align=align, extra_align=extrasize_align, orient=orient, orient_ref=[0,0,1], roll=roll, , extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    {
        cube(size+extrasize, center=true);
    }
}

module rcubea(size=[10,10,10], rounding_radius=1, align=[0,0,0], extrasize=[0,0,0], extrasize_align=[0,0,0], orient=[0,0,1], roll=0, extra_roll, extra_roll_orient)
{
    size_align(size=size,extra_size=extrasize, align=align, extra_align=extrasize_align, orient=orient, orient_ref=[0,0,1], roll=roll, extra_roll=extra_roll, extra_roll_orient=extra_roll_orient)
    {
        rcube(size=size+extrasize, rounding_radius=rounding_radius);
    }
}

/*cubea(size=[10,20,30], align=[0,-1,0], orient=[0,0,1], roll=10, extra_roll=-30, extra_roll_orient=[1,0,0]);*/

module rcube(size=[20,20,20], rounding_radius=1)
{
    if($preview_mode || rounding_radius == 0)
    {
        cubea(size);
    }
    else
    {
        hull()
        for(x=[-(size[0]/2-rounding_radius),(size[0]/2-rounding_radius)])
        for(y=[-(size[1]/2-rounding_radius),(size[1]/2-rounding_radius)])
        for(z=[-(size[2]/2-rounding_radius),(size[2]/2-rounding_radius)])
        translate([x,y,z])
        sphere(r=rounding_radius);
    }
}

module cylindera(
        h=10,
        r=undef,
        r1=undef,
        r2=undef,
        d=undef,
        d1=undef,
        d2=undef,
        align=[0,0,0],
        orient=[0,0,1],
        extra_h=0,
        extra_r=undef,
        extra_d=undef,
        extra_align=[0,0,0],
        round_radius=0,
        debug=false
        )
{
    pi=3.1415926536;

    d1_ = v_fallback(d1, [r*2, r1*2]);
    d2_ = v_fallback(d2, [r*2, r2*2]);

    r1_ = v_fallback(r1, [d1_/2, d/2, r]);
    r2_ = v_fallback(r2, [d2_/2, d/2, r]);

    r_max = v_fallback(r, [max(r1_,r2_)]);

    extra_r_ = v_fallback(extra_r, [0]);

    if(debug)
    {
        echo(useDia, h, r_, r1_, r2_, extra_r_, align);
    }

    size_align(size=[r_max*2,r_max*2,h], extra_size=[extra_r_*2, extra_r_*2, extra_h], orient=orient, orient_ref=[0,0,1], align=align, extra_align=extra_align)
    {
        if(round_radius>0)
        {
            rcylindera(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, round_radius=round_radius);
        }
        else
        {
            cylinder(h=h+extra_h, r1=r1_+extra_r_, r2=r2_+extra_r_, center=true);
        }
    }
}

/*translate([10,0,0])*/
/*rotate_extrude()*/
        /*translate([10-2,2,0])*/
/*$fa = 5.6;*/
/*$fs = 0.3;*/
/*circle(r = 100);*/
/*torus(10, 2, align=[0,0,0], orient=[0,0,1]);*/

module torus(radius, radial_width, align=[0,0,0], orient=[0,0,1])
{
    size_align(size=[radius*2+radial_width*2, radius*2+radial_width*2, radial_width*2], align=align, orient=orient)
    rotate_extrude()
    translate([radius, 0, 0])
    circle(radial_width);
}

module rcylindera(d, d1, d2, r, r1, r2, h=10, round_radius=2, align=[0,0,0], orient=[0,0,1])
{
    if($preview_mode || round_radius == 0 || true)
    {
        cylindera(d=d, d1=d1, d2=d2, r=r, r1=r1, r2=r2, h=h, align=align, orient=orient);
    }
    else
    {
        d1_ = v_fallback(d1, [r*2, r1*2]);
        d2_ = v_fallback(d2, [r*2, r2*2]);

        r1_ = v_fallback(r1, [d/2, d1_/2]);
        r2_ = v_fallback(r2, [d/2, d2_/2]);

        r_ = [r1_,r2_];

        size_align(align=align, orient=orient)
            hull()
            {
                for(z=[-1,1])
                    translate([0, 0, z*(-h/2)])
                    {
                        r__=z!=-1?r_[0]:r_[1];
                        torus(radius=r__-round_radius/2, radial_width=round_radius/2, align=[0,0,z]);
                    }
            }
    }
}

// positive angles go from start to end counterclockwise
// negative angles are allowed
module pie_slice_shape(r, start_angle, end_angle) {
    R = r * sqrt(2) + 1;
    a0 = (4 * start_angle + 0 * end_angle) / 4;
    a1 = (3 * start_angle + 1 * end_angle) / 4;
    a2 = (2 * start_angle + 2 * end_angle) / 4;
    a3 = (1 * start_angle + 3 * end_angle) / 4;
    a4 = (0 * start_angle + 4 * end_angle) / 4;
    intersection() {
        circle(r);
        polygon([
                [0,0],
                [R * cos(a0), R * sin(a0)],
                [R * cos(a1), R * sin(a1)],
                [R * cos(a2), R * sin(a2)],
                [R * cos(a3), R * sin(a3)],
                [R * cos(a4), R * sin(a4)],
                [0,0]
        ]);
    }
}

// positive angles go from start to end counterclockwise
// negative angles are allowed
module pie_slice(r, start_angle, end_angle, h, orient=[0,0,1], align=[0,0,0])
{
    size_align(size=[r*2, r*2, h], orient=orient, orient_ref=[0,0,1], align=align)
    linear_extrude(h)
    {
        pie_slice_shape(r, start_angle, end_angle);
    }
}

module hollow_cylinder(d=10, thickness=1, h=10, taper=false, taper_h=undef, orient=[0,0,1], align=[0,0,0])
{
    outer_d = d+thickness/2;
    inner_d = d-thickness/2;
    taper_h = taper_h == undef ? min(h/4, (outer_d-inner_d)/2) : max(taper_h,h/2);
    taper_ = taper && taper_h > 0;
    size_align(size=[outer_d, outer_d, h], orient=orient, align=align);
    difference()
    {
        union()
        {
            cylindera(h=h-(taper_?taper_h*2:0), d=outer_d, orient=[0,0,1], align=[0,0,0]);
            if(taper_)
            {
                for(z=[-1,1])
                translate([0,0,z*(h/2-taper_h)])
                mirror([0,0,z==-1?1:0])
                cylindera(d1=outer_d, d2=outer_d-inner_d/4, h=taper_h, align=[0,0,1]);
            }
        }
        if(taper_)
        {
            for(z=[-1,1])
            translate([0,0,z*(h/2-taper_h)])
            mirror([0,0,z==-1?1:0])
            cylindera(d1=inner_d, d2=outer_d, h=taper_h+.1, align=[0,0,1]);

            // override fn for inner cylinder cut, to ensure same fragments as taper
            // this ensures cleaner mesh
            fn = fn_from_d(d=outer_d);
            cylindera(h=h+.2+taper_h, d=inner_d, orient=[0,0,1], align=[0,0,0], $fn=fn);
        }
        else
        {
            cylindera(h=h+.2, d=inner_d, orient=[0,0,1], align=[0,0,0]);
        }
    }
}

/**
 * Standard right-angled triangle
 *
 * @param number o_len Lenght of the opposite side
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 * @todo a better way ?
 */
module triangle(o_len, a_len, depth, align=[0,0,0], orient=[0,0,1])
{
    size_align(size=[a_len, depth, o_len], align=align, orient=orient)
    rotate([90,0,0])
    translate([-a_len/2, -o_len/2, -depth/2])
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,o_len]], paths=[[0,1,2]]);
    }
}

/**
 * Rounded Standard right-angled triangle
 *
 * @param number o_len Lenght of the opposite side
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 * @todo a better way ?
 */
module rtriangle(o_len, a_len, depth, rounding_radius=2, align=[0,0,0], orient=[0,0,1])
{
    size = [a_len-rounding_radius, depth-rounding_radius, o_len-rounding_radius];
    r_x = rounding_radius;
    r_y = rounding_radius;
    r_z = -rounding_radius;

    hyp = pythag_hyp(o_len,a_len);
    a_z = atan(a_len/o_len);

    translate([0,0,size[2]+2])
    color([1,0,0])
    rotate([90,90,0])
    pie_slice(r=2, start_angle=0, end_angle=a_z, h=depth);

    /*translate([size[0]+4,0,0])*/
    /*color([1,0,0])*/
    /*rotate([90,90,0])*/
    /*pie_slice(r=2, start_angle=90, end_angle=90+a_z, h=depth);*/

    size_align(size=size, align=align, orient=orient)
    /*hull()*/
    for(x=[-(size[0]/2)+rounding_radius,(size[0]/2)-r_x])
    for(y=[-(size[1]/2)+rounding_radius,(size[1]/2)-r_y])
    for(z=[-(size[2]/2)+rounding_radius,(size[2]/2)-r_z])
    translate([x,y,z])
    if(x<=1 || z<=1)
    sphere(r=rounding_radius);
}

module teardrop(r, d, h=10, truncate=1, align=[0,0,0], orient=[0,1,0], roll=0)
{
    r_= v_fallback(r, [d/2]);

    sx1 = r_ * sin(-45);
    sx2 = r_ * -sin(-45);
    sy = r_ * -cos(-45);
    ex = 0;
    ey = (sin(-135) + cos(-135)) * r_;

    dx= ex-sx1;
    dy = ey-sy;

    eys = lerp(-r_,ey,1-truncate);

    dys = eys-sy;
    ex1 = sy+dys*dx/dy;
    ex2 = -ex1;

    size_align(size=[d,d,h], align=align, orient=orient, orient_ref=[0,0,1], roll=roll)
    union()
    {
        linear_extrude(height = h, center = true, convexity = r_, twist = 0)
        circle(r = r_, center = true);

        linear_extrude(height = h, center = true, convexity = r_, twist = 0)
        polygon(points = [
                [sy, sx1],
                [sy, sx2],
                [eys, ex2],
                [eys, ex1]],
                paths = [[0, 1, 2, 3]]);
    }
}

// test teardrop
if(false)
{
    r=5*mm;
    for(axis=concat(AXES,-AXES))
    translate(axis*r*2)
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        teardrop(r=r, h=20, orient=axis, align=axis);
    }
}

// test cubea
if(false)
{
    w=5*mm;
    h=2*mm;
    for(axis=concat(AXES,-AXES))
    /*translate(axis)*/
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        cubea([w,w,h], orient=axis, align=axis*3);
    }
}
/**
/*debug();*/

module debug()
{
    $fs = 0.1;
    $fa = 1;

    /*triangle_a(45, 5, 5);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=[0,0,-1]);*/
    /*triangle(15, 10, 5, align=[1,1,1], orient=[0,0,1]);*/

    triangle(10, 30, 5, align=[1,1,1], orient=[0,0,1]);
    translate([0,-10,0])
    rtriangle(10, 30, 5, align=[1,1,1], orient=[0,0,1]);
}

/**
 * Standard right-angled triangle (tangent version)
 *
 * @param number angle of adjacent to hypotenuse (ie tangent)
 * @param number a_len Lenght of the adjacent side
 * @param number depth How wide/deep the triangle is in the 3rd dimension
 */
module triangle_a(tan_angle, a_len, depth)
{
    linear_extrude(height=depth)
    {
        polygon(points=[[0,0],[a_len,0],[0,tan(tan_angle) * a_len]], paths=[[0,1,2]]);
    }
}

// Tests:
module test_triangles()
{
    // Generate a bunch of triangles by sizes
    for (i = [1:10])
    {
        translate([i*7, -30, i*7])
        {
            triangle(i*5, sqrt(i*5+pow(i,2)), 5);
        }
    }

    // Generate a bunch of triangles by angle
    for (i = [1:85/5])
    {
        translate([i*7, 22, i*7])
        {
            triangle_a(i*5, 10, 5);
        }
    }
}

if(false)
{
    stack(axis=XAXIS, dist=15)
    {
        hollow_cylinder(thickness=5, h=10, taper=false, orient=[0,0,1], align=[0,0,1]);
        hollow_cylinder(thickness=5, h=10, taper=true, orient=[0,0,1], align=[0,0,1]);
    }

    /*cylindera(d=10, h=10, orient=[0,0,1], align=[0,0,1]);*/
    /*translate([10,0,0])*/
    /*{*/
    /*hollow_cylinder(d=10, thickness=4, h=10, taper=true, taper_h=.5, orient=[0,0,1], align=[0,0,1]);*/
    /*cylindera(d=8, h=10, orient=[0,0,1], align=[0,0,1]);*/
    /*}*/

    /*%pie_slice(r=10, start_angle=-30, end_angle=270, h=10);*/

    /*cubea([10,10,10],[1,0,0]);*/
    /*%cubea([10,10,10],[1,0,0],[5,5,5],[1,1,1]);*/

    /*%cubea([10,10,10],[-1,0,1]);*/
    /*%cubea([10,10,10],[-1,0,1],[1,1,1],[-1,0,1]);*/
    /*%cylindera(h=10, r=10/2, align=[-1,1,1], extra_r=5/2, extra_h=2, extra_align=[-1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=[-1,1,1], extra_d=5, extra_h=2, extra_align=[-1,1,1], $fn=100);*/
    /*%cylindera(h=10, d=10, align=[1,1,1], extra_d=15, extra_h=2, extra_align=[1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=[1,-1,1], extra_d=5, extra_h=2, extra_align=[-1,-1,1], $fn=100);*/
    /*%cylindera(h=10, d=10, align=[1,1,1], extra_d=5, extra_h=2, extra_align=[1,1,1], $fn=100);*/

    /*%cylindera(h=10, d=10, align=[1,0,0], extra_d=10);*/

    /*hull_pairwise()*/
    /*sphere(30/2);*/

    /*translate([30,0,0])*/
    /*rcubea(s=[35,35,35], rounding_radius=10);*/
    /*rcubea(s=[35,35,35], align=[0,-1,0]);*/

    /*translate([60,0,0])*/
    /*sphere(30/2);*/

    cylindera(h=20, r=5*mm, align=[0,1,0], orient=[0,0,1], $fn=100);

/*size_align(size=[5,5,20], orient=[0,1,0], orient_ref=[0,0,1])*/
/*size_align(size=[5,5,20], orient=[0,1,0], orient_ref=[0,1,0], align=[0,1,0])*/
/*size_align(size=[5,20,5], orient=[0,0,1], orient_ref=[0,1,0], align=[0,0,0])*/
/*rotate([90,0,0])*/
/*cylinder(d=5, h=20, center=true);*/

/*cylindera(d=10, h=10, orient=[0,1,0], align=[0,0,1]);*/
}

if(false)
{
    r=5*mm;
    for(axis=concat(AXES,-AXES))
    translate(axis*r*2)
    {
        c= v_abs(axis*.3 + v_clamp(v_sign(axis),0,1)*.7);
        color(c)
        /*cylindera(h=20, r=r, align=axis, orient=axis, extra_h=r, extra_align=-axis, $fn=100);*/
        cylindera(h=20, r1=r, r2=r/2, align=axis, orient=axis, extra_h=r, extra_align=-axis, $fn=16, round_radius=2);
    }
}

if(false)
{
    stack(dist=50, axis=[0,1,0])
    {
        stack(dist=10, axis=[0,0,-1])
        {
            /*cylindera(orient=[0,0,-1], align=[0,0,-1]);*/
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=[0,0,1], align=[0,0,-1]);
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=[0,0,-1], align=[0,0,1]);
            /*pie_slice(r=30, h=5, start_angle=-90, end_angle=180, align=[0,0,-1]);*/
            /*pie_slice(r=30, h=5, start_angle=90, end_angle=270, align=[0,0,-1]);*/
            /*pie_slice(r=30, h=5, start_angle=0, end_angle=270, align=[0,0,-1]);*/
        }

        stack(dist=10, axis=[0,1,0])
        {
            /*cylindera(orient=[0,1,0], align=[0,1,0]);*/
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=[0,-1,0], align=[0,1,0]);
            pie_slice(r=30, h=5, start_angle=0, end_angle=120, orient=[0,1,0], align=[0,1,0]);
            pie_slice(r=30, h=5, start_angle=-90, end_angle=180, orient=[0,1,0], align=[0,1,0]);
            pie_slice(r=30, h=5, start_angle=90, end_angle=270, orient=[0,1,0], align=[0,1,0]);
            pie_slice(r=30, h=5, start_angle=0, end_angle=270, orient=[0,1,0], align=[0,1,0]);
        }
    }
}