Skip to content

Instantly share code, notes, and snippets.

@ochafik
Last active December 12, 2023 05:11
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save ochafik/70a6b15e982b7ccd5a79ff9afd99dbcf to your computer and use it in GitHub Desktop.
Save ochafik/70a6b15e982b7ccd5a79ff9afd99dbcf to your computer and use it in GitHub Desktop.
OpenSCAD + Manifold rendering time examples
out
*.stl
libs

OpenSCAD + Manifold = ❤️

Benchmark scripts & results for the upcoming Manifold rendering engine support in OpenSCAD (openscad/openscad#4533)

TL;DR: Jump to results already!

For reference: old benchmarks of fast-csg, which the Manifold backend might well soon replace!

Note that minkowski operations get a specific boost thanks to the introduction of parallelism in the algorithm itself (and then the union of parts it generates benefits from Manifold's own parallelism)

Running the benchmarks yourself on your own files

export OPENSCAD=$PWD/OpenSCAD.app/Contents/MacOS/OpenSCAD
# export OPENSCAD=$PWD/openscad

git clone https://gist.github.com/ochafik/70a6b15e982b7ccd5a79ff9afd99dbcf openscad-manifold-benchmarks
cd openscad-manifold-benchmarks
./get_libs # Will fetch lots of common libs

RUNS=5 ./bench bolts.scad
# ./bench *.scad 

Each run outputs a timestamped JSON results file. Multiple files can be merge-analyzed to generate a markdown table and human summary:

./analyze_results out/results-3-files-5-variants-20230317-1944.json out/threads-20230317-1943.json

Also, if file.scad file has a companion file.json with customizer parameter sets, all the sets will be executed. Specify file.scad: to only execute the file with its default values, or specify a single parameter set by name file.scad:my parameter set name.

You can generate custom parameter sets with the following helper:

./gen_param_sets 'N=[2,10]' '$fn=[20,100]' | tee scalemail.json
{
    "fileFormatVersion": "1",
    "parameterSets": {
        "N=2 $fn=20": {
            "N": "2",
            "$fn": "20"
        },
        "N=2 $fn=100": {
            "N": "2",
            "$fn": "100"
        },
        "N=10 $fn=20": {
            "N": "10",
            "$fn": "20"
        },
        "N=10 $fn=100": {
            "N": "10",
            "$fn": "100"
        }
    }
}

These will be picked up automatically by ./bench scalemail.scad

Results

File Speed-up CPU utilization manifold fast-csg nef
condensed-matter.scad 8.3x 2.6 cores 0.99 seconds 8.25 seconds
condensed-matter.scad:$fn=100 19.9x 3.2 cores 27.16 seconds 8 minutes and 59.73 seconds
examples/Parametric/candleStand.scad:small 32.3x 2.4 cores 0.25 seconds 49.16 seconds 8.05 seconds
bolts.scad 8.9x 1.3 cores 4.59 seconds 40.82 seconds
box-with-filleted-holes.scad 9.6x 2.9 cores 10.61 seconds 1 minute and 42.3 seconds 18 minutes and 52.35 seconds
libs/github.com/rcolyer/threads-scad/threads.scad 13.1x 1.5 cores 1.39 seconds 18.27 seconds 1 minute and 9.41 seconds
maze.scad: 27.7x 2.6 cores 3.35 seconds 5 minutes and 32.25 seconds 1 minute and 32.68 seconds
menger.scad 36.7x 3.9 cores 5.08 seconds 3 minutes and 6.14 seconds 4 minutes and 53.86 seconds
minkowski-of-minkowski-difference.scad 1.0 1.8 cores 42.85 seconds 43.59 seconds 3 minutes and 34.84 seconds
scalemail.scad 3.6x 2.4 cores 0.61 seconds 2.17 seconds
scalemail.scad:N=10 $fn=100 19.8x 3.1 cores 20.29 seconds 6 minutes and 41.64 seconds
scalemail.scad:N=10 $fn=20 15.1x 2.7 cores 2.01 seconds 30.39 seconds
scalemail.scad:N=2 $fn=100 5.3x 3.5 cores 9.25 seconds 49.12 seconds
scalemail.scad:N=2 $fn=20 3.5x 2.3 cores 0.61 seconds 2.15 seconds
smoothed-antennas.scad 20.5x 6.0 cores 38.07 seconds 13 minutes and 1.15 seconds
smoothed-cup.scad 6.4x 2.9 cores 4.42 seconds 28.5 seconds 4 minutes and 20.81 seconds

Notes:

  • Speed-up is over the fastest of fast-csg and nef (nef = normal rendering used in the stable releases).
  • fast-csg and nef never use more than 1 core
  • fast-csg has all the related options turned on: fast-csg-remesh (which keeps the # of faces in check by remeshing solids after each corefinement), fast-csg-exact and fast-csg-exact-callbacks (which force lazy numbers to exact after - or during - each operation), fast-csg-trust-corefinement (which tries corefinement even in edge cases where we know it might not work)
  • All timings are on a Mac M2 Max (w/ a single run). Please let me know if you see significant speedup differences on other platforms.

Interpretation

  • 🎉 OpenSCAD+Manifold is 5-30x faster than OpenSCAD+fast-csg (CGAL corefinement w/ a Nef fallback). The reasons for that are many:
    • it doesn't use exact rationals (mere single-precision floats), which are slow and (in their lazy CGAL::Epeck wrappers) have suprising performance characteristics (which I tried to work around with all the exact-forcing options)
    • it's multithreaded (even though I didn't build w/ CUDA support, just w/ CPU multithreading using TBB),
    • it does not fall back to Nef CSG operations. Well, ok, it does use Nefs to perform convex parts decomposition, and in case of exception it will fall back to Nef minkowski, but normal CSG ops are 100% handled by Manifold.
  • ❌ One model is surprisingly not improving (minkowski-of-minkowski-difference.scad), needs investigation! Lemme know if you find more like this!
  • ⚠️ More testing (esp. re/ output quality) is needed! Besides normal bugs, there might be cases where the single precision bites, say, with lots of nested up/down scalings. I have plans to flatten the tree in openscad/openscad#4561 to help deal with that.
  • ⚠️ Manifold might be more picky with input meshes, rejecting more eagerly invalid geometry. Mostly a backwards compatibility issue, but maybe we could fix some meshes if that's too widespread an issue.
  • 🎉 Manifold is the way to go. It's fast (and will only get better, its code base seems to have room for more parallelism), allows for safe parallel algorithms (like the minkowski variant I've thrown in, which itself has room for more parallelism), and it seems to have more predictible performance than CGAL's corefinement (numbers above are single runs, but if you run with RUNS=10 ./bench ... you'll see the variance of fast-csg is much higher for some reason!).
  • 🎉 Some models are slower w/ fast-csg than nef. This could be because of Nef fallbacks, issues w/ my remeshing, high cost of forcing numbers to exact, etc. But Manifold crunches through these models for breakfast, so who cares?

Some screenshots of the associated models (which source is below):

  • box-with-filleted-holes.scad

image

  • smoothed-cup.scad

image

  • smoothed-antennas.scad: taken from BOSL's docs, with extra minkowski and detail.

image

  • minkowski-of-minkowski-difference.scad: This isn't so fast, need to understand why

image

#!/usr/bin/python3
# Copyright 2021 Google LLC.
# SPDX-License-Identifier: Apache-2.00
import sys, json
import itertools
from humanfriendly import format_timespan
results = []
# mode = sys.argv[1]
# files = sys.argv[2:]
files = sys.argv[1:]
if len(files) == 0:
results += json.load(sys.stdin)['results']
else:
for file in files:
with open(file) as f:
results += json.load(f)["results"]
def get_file(r):
return r["parameters"]["file"]
def get_mode(r):
return r["parameters"]["mode"]
def get_result_with_mode(rs, mode):
matches = list(filter(lambda r: get_mode(r) == mode, rs))
if len(matches) == 0:
return None
return matches[0]
def get_cores(r):
return (r["user"] + r["system"]) / r["mean"]
def summarize(file, rs, md):
manifold = get_result_with_mode(rs, "manifold")
cores = '%.1f' % get_cores(get_result_with_mode(rs, "manifold"))
fastcsg = get_result_with_mode(rs, "fastcsg")
nef = get_result_with_mode(rs, "nef")
fastest_other = min(map(lambda x: x["mean"], filter(lambda x: x, [fastcsg, nef])), default=None)
faster = ''
if fastest_other:
faster = '%.1fx' % (fastest_other / manifold["mean"])
manifold_time = format_timespan(manifold["mean"])
fastcsg_time = ''
if fastcsg:
fastcsg_time = format_timespan(fastcsg["mean"])
nef_time = ''
if nef:
nef_time = format_timespan(nef["mean"])
if md:
return f'| {file} | {faster} | {cores} cores | {manifold_time} | {fastcsg_time} | {nef_time} |'
else:
lines=[
f'# {file}',
f'\tmanifold: {manifold_time} ({faster} faster, {cores} cores)',
]
if fastcsg:
lines.append(f'\tfast-csg: {fastcsg_time}')
if nef:
lines.append(f'\tnef: {nef_time}')
return '\n'.join(lines)
data = [
(file, list(rs)) for file, rs in itertools.groupby(sorted(results, key=get_file), get_file)
]
# print(data)
# if mode == "md":
for md in [False, True]:
if md:
print('')
print('| File | Speed-up | CPU utilization | manifold | fast-csg | nef |')
print('|:-----|---------:|----------------:|---------:|---------:|----:|')
print('\n'.join([summarize(file, rs, md=True) for file, rs in data]) + '\n')
else:
print('\n\n'.join([summarize(file, rs, md=False) for file, rs in data]) + '\n')
#!/bin/bash
# Copyright 2021 Google LLC.
# SPDX-License-Identifier: Apache-2.00
#
# ./bench foo.scad
#
set -euo pipefail
RUNS=${RUNS:-1}
export OUTPUT_DIR=${OUTPUT_DIR:-$PWD/out}
mkdir -p "$OUTPUT_DIR"
LIBS_DIR=${LIBS_DIR:-$PWD/libs}
test -d "$LIBS_DIR" || ./get_libs
modes=( manifold )
if [[ "${FASTCSG:-1}" == "1" ]]; then
modes+=( fastcsg )
fi
if [[ "${NEF:-0}" == "1" ]]; then
modes+=( nef )
fi
# Note: ~/Documents/OpenSCAD/libraries also on path on Mac
export OPENSCADPATH=$LIBS_DIR:${OPENSCADPATH:-}
function join_by {
local IFS="$1"
shift
echo "$*"
}
function parse_parameter_set_names() {
python3 -c "import sys, json; print('\n'.join(json.load(sys.stdin)['parameterSets'].keys()))"
}
files=()
for scad_file in "$@" ; do
files+=( "$scad_file" )
json_file="${scad_file%.scad}.json"
if [[ -f "$json_file" ]]; then
set_names="$( cat "$json_file" | parse_parameter_set_names )"
while IFS= read -r setting
do
files+=( "$scad_file:$setting" )
done <<< "$set_names"
fi
done
if [[ "$#" -eq 1 ]]; then
OUTPUT_NAME_PREFIX="$( basename "${1%.scad}" )"
else
OUTPUT_NAME_PREFIX="results-$#-files"
fi
if [[ "${#files[@]}" -eq "$#" ]]; then
OUTPUT_NAME="${OUTPUT_NAME_PREFIX}"
else
OUTPUT_NAME="${OUTPUT_NAME_PREFIX}-${#files[@]}-variants"
fi
TIMESTAMP=$( gdate '+%Y%m%d-%H%M' )
OUTPUT_PREFIX="$OUTPUT_DIR/$OUTPUT_NAME-$TIMESTAMP"
hyperfine_args=(
-i
-L mode "$( join_by , "${modes[@]}" )"
-L file "$( join_by , "${files[@]}" )"
--runs "$RUNS"
--export-json "$OUTPUT_PREFIX.json"
# --export-markdown "$OUTPUT_PREFIX.md"
"./render {mode} '{file}'"
)
echo "# Output will go in $OUTPUT_PREFIX.json"
hyperfine "${hyperfine_args[@]}"
./analyze_results "$OUTPUT_PREFIX.json"
# ./analyze_results human "$OUTPUT_PREFIX.json"
# ./analyze_results md "$OUTPUT_PREFIX.json" > $OUTPUT_PREFIX.md
use <threadlib/threadlib.scad>
use <threads.scad>
//minkowski()
{
union() {
for (M=[1:8])
translate([M*M,0,0])
bolt(str("M", M), turns=5, higbee_arc=30);
for (i=[0:8])
let(M=4+i)
translate([i*20,20,0])
nut(str("M", M, "x0.5"), turns=10, Douter=16);
}
//sphere(d=0.5, $fn=10);
}
//bolt("M4", turns=5, higbee_arc=30);
//nut("M12x0.5", turns=10, Douter=16);
include <BOSL2/std.scad>
dims=[100, 200, 30];
holes=[5, 10];
border=10;
smoothRadius=2;
smoothFn=$preview ? 5 : 30;
holeDiam=10;
holeFn=$preview ? 10 : 30;
minkowski() {
union() {
difference() {
cube(dims);
translate([border, border, border])
cube(dims - 2 * [border, border, 0]);
for (i=[0:holes[0]], j=[0:holes[1]])
translate([
border + (i + 0.5) * (dims[0] - 2 * border) / (holes[0] + 1),
border + (j + 0.5) * (dims[1] - 2 * border) / (holes[1] + 1),
0
])
cylinder(h = border, d=holeDiam, $fn=holeFn);
}
}
sphere(smoothRadius, $fn=smoothFn);
}
// Parametric divided storage box OpenSCAD source.
// Project Home: https://hackaday.io/project/164516/
// Author: https://hackaday.io/daren
//
// Creative Commons License exists for this work. You may copy and alter the content
// of this file for private use only, and distribute it only with the associated
// Parametric divided storage box content. This license must be included with
// the file and content.
// For a copy of the current license, please visit http://creativecommons.org/licenses/by/2.0/
cols=[7.2,7.2,7.2,7.2,7.2,7.2,7.2,7.2,7.2,7.2,7.2]; // col widths
rows=[8.5,8.5,8.5,8.5,8.5]; // row widths
pin_d=1; // hinge pin diameter
lid_h=6; // lid height
box_h=8.5; // box height
hinge_clearance=0.2; // clearance for hinge rotation
walls=[1.2,1.6,0.3,0.4]; // inner,outer,top,bottom
hinge_d=pin_d+2.4;
$fn=30;
extra=0.01;
w=array_sum(cols);
l=array_sum(rows);
total_w=w-walls[0]+walls[1]*2;
total_l=l-walls[0]+walls[1]*2;
//assembly(offset=4);
minkowski() {
box();
//lid();
sphere(1, $fn=100);
}
module assembly(offset=0) {
box();
translate([0,l+walls[1]*2-hinge_clearance+offset,box_h-lid_h]) lid();
}
module box() {
difference() {
union() {
translate([0,0,box_h/2]) cube([total_w,total_l,box_h],center=true);
translate([0,(total_l+hinge_d/4+hinge_clearance)/2,box_h]) hull() {
rotate([0,90,0]) cylinder(r=hinge_d/2,h=total_w,center=true);
translate([0,-hinge_d/4,-hinge_d*.85]) cube([total_w,extra,extra],center=true);
}
hull() for(i=[-1,1]) translate([i*w/6,-total_l/2,box_h/8]) scale([1,0.75,1]) sphere(r=box_h/8,center=true);
}
translate([-w/2,(total_l+hinge_d/4+hinge_clearance)/2,box_h]) build_box_hinge();
translate([0,-(total_l+walls[1])/2,box_h]) for(i=[-1,1]) translate([i*w/6,1,-box_h/4-hinge_clearance]) scale([1,0.95,1.5]) sphere(r=box_h/8,center=true);
translate([-w/2,-l/2,box_h/2+walls[3]]) build_rows(0,0,walls[0]*2);
translate([0,(total_l+hinge_d/4+hinge_clearance)/2,box_h]) rotate([0,90,0]) cylinder(r=pin_d/2,h=total_w+extra,center=true);
}
}
module lid() {
difference() {
union() {
translate([0,0,(lid_h-hinge_clearance)/2]) cube([total_w,total_l,lid_h-hinge_clearance],center=true);
translate([0,(total_l+walls[1]+hinge_clearance/2)/2,lid_h]) hull() {
for(i=[-1,1]) translate([i*w/6,-walls[1]/4,box_h/4]) rotate([90,0,0]) cylinder(r=hinge_d/2,h=walls[1]/2,center=true);
translate([0,-walls[1]/2-hinge_clearance/4,-lid_h]) cube([w/2+walls[1]+pin_d,extra,extra],center=true);
translate([0,0,-lid_h/2]) cube([w/2+walls[1]+pin_d,walls[1],extra],center=true);
}
hull() for(i=[-1,1]) translate([i*w/6,total_l/2+walls[1]*.75,lid_h]) {
scale([1,0.75,1.5]) sphere(r=box_h/8,center=true);
translate([0,-walls[1]/2,-hinge_clearance-box_h/8]) cube([box_h/4,walls[1]/2,box_h/4],center=true);
}
translate([0,(total_l+walls[1])/2,lid_h]) for(i=[-1,1]) translate([i*w/6,-box_h/15,box_h/4]) scale([1,0.75,1.25]) sphere(r=box_h/8,center=true);
translate([0,-(total_l+hinge_d/4+hinge_clearance)/2,lid_h]) hull() {
rotate([0,90,0]) cylinder(r=hinge_d/2,h=total_w,center=true);
translate([0,hinge_d/4,-hinge_d*.85]) cube([total_w,extra,extra],center=true);
}
}
difference() {
translate([0,0,lid_h/2+walls[2]/2]) cube([total_w-walls[1]*2,total_l-walls[1]*2,lid_h-walls[2]],center=true);
translate([0,-(total_l+hinge_d/4+hinge_clearance)/2,lid_h]) hull() {
rotate([0,90,0]) cylinder(r=hinge_d/2,h=total_w,center=true);
translate([0,hinge_d/4,-hinge_d*.85]) cube([total_w,extra,extra],center=true);
}
}
translate([0,-(total_l+hinge_d/4+hinge_clearance)/2,lid_h]) {
rotate([0,90,0]) cylinder(r=pin_d/2,h=total_w+extra,center=true);
translate([-w/2,0,0]) build_lid_hinge();
for(i=[-1,1]) translate([i*(total_w-walls[1])/2,0,0]) hull() {
rotate([0,90,0]) cylinder(r=hinge_d/2+hinge_clearance/2,h=walls[1]+hinge_clearance,center=true);
translate([0,hinge_clearance/2,-hinge_d*.85]) cube([walls[1]+hinge_clearance,extra,extra],center=true);
}
}
translate([0,0,-box_h/2]) cube([total_w,total_l,box_h],center=true);
}
}
module build_lid_hinge(col=0,offset=walls[0]) {
if (col % 2 != 0) translate([cols[col]/2,0,0]) hull() {
rotate([0,90,0]) cylinder(r=hinge_d/2+hinge_clearance/2,h=cols[col]+offset+hinge_clearance,center=true);
translate([0,0,-hinge_d*.85]) cube([cols[col]+offset+hinge_clearance,extra,extra],center=true);
}
if (col<len(cols)-1) translate([cols[col],0,0]) build_lid_hinge(col+1);
}
module build_box_hinge(col=0,offset=walls[0]) {
if (col % 2 == 0) translate([cols[col]/2,0,0]) hull() {
rotate([0,90,0]) cylinder(r=hinge_d/2+hinge_clearance/2,h=cols[col]-offset,center=true);
translate([0,0,-hinge_d*.85]) cube([cols[col]-offset,extra,extra],center=true);
}
if (col<len(cols)-1) translate([cols[col],0,0]) build_box_hinge(col+1);
}
module build_rows(col=0,row=0,offset=walls[0]) {
translate([0,rows[row]/2,0]) {
if (row<len(rows)-1) translate([0,rows[row]/2,0]) build_rows(col,row+1,offset);
build_cols(col,row,offset);
}
}
module build_cols(col,row,offset=walls[0]) {
translate([cols[col]/2,0,0]) {
cube([cols[col]-offset/2,rows[row]-offset/2,box_h],center=true);
if (col<len(cols)-1) translate([cols[col]/2,0,0]) build_cols(col+1,row,offset);
}
}
function array_sum(arr,c=0) = c < len(arr) - 1 ? arr[c] + array_sum(arr, c + 1) : arr[c];
$fn=200;
length = 86;
width= 46;
height = 19;
cornerRadius = 10;
translate([10, 10, 0]){
difference() {
roundedBox(length, width, height, cornerRadius);
translate([1,1,1]) {
roundedBox(length-2, width-2, height-1, cornerRadius);
}
}
}
module roundedBox(length, width, height, radius)
{
dRadius = 2*radius;
//cube bottom right
translate([width-dRadius,-radius,0]) {
cube(size=[radius,radius,height+0.01]);
}
//cube top left
translate([-radius,length-dRadius,0]) {
cube(size=[radius,radius,height+0.01]);
}
//base rounded shape
minkowski() {
cube(size=[width-dRadius,length-dRadius, height]);
cylinder(r=radius, h=0.01);
}
}
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
//
// This one has local overlaps all over the place, and needs a heuristic to find non-overlapping subsets.
// (that's under development, expect CGAL::hilbert_sort, CGAL::Union_find and hopefully some good benchmarks!)
$fn=20;
step = 0.01; //$preview ? 0.01 : 0.001;
thickness = 0.5;
height = 1;
r1 = 2;
r2 = 3;
N = 5;
stride = r1 + r2;
// Use sweep.scad
use_sweep = false;
function f(t, r1, r2, h, m=4, n=1) =
let (avgRadius = (r1 + r2) / 2)
[
cos(n * t) * (avgRadius + (r2 - r1) / 2 * cos(m * t)),
sin(n * t) * (avgRadius + (r2 - r1) / 2 * cos(m * t)),
h * sin(m * t)
];
use <list-comprehension-demos/sweep.scad>
use <scad-utils/shapes.scad>
module draw_curve_sweep(p, thickness)
sweep(circle(thickness / 2), construct_transform_path(p), true);
module draw_curve(p, thickness)
if (use_sweep)
draw_curve_sweep(p, thickness);
else
for (i=[0:len(p)-2])
hull() {
translate(p[i]) sphere(d=thickness);
translate(p[i+1]) sphere(d=thickness);
}
module torus_knot() {
points = [for (t=[0:step:1]) f(t * 360, r1=r1, r2=r2, h=height)];
draw_curve(points, thickness);
}
translate([-N * stride / 2 + stride / 2, -N * stride / 2 + stride / 2, height + thickness / 2]) {
for (i=[0:N-1], j=[0:N-1]) translate([i * stride, j * stride,0])
torus_knot();
}
{
"fileFormatVersion": "1",
"parameterSets": {
"$fn=100": {
"$fn": "100"
}
}
}
//Condensed matter
//All measurements are in Ångstrom
//OpenSCAD
$fn = 16; //sections per circle
echo(version=version());
//Liquid nitrogen (N2)
AtomicRadiusN2 = 0.65;
BondPairN2 = 1.197;
ColorN2 = "Silver";
echo(pow(BondPairN2,1/3));
//Silicon (Si)
AtomicRadiusSi = 1.1;
LatticeCellSizeSi = 5.4309;
fccOffset = 0.25;
ColorSi = "Wheat";
echo(fccOffset * LatticeCellSizeSi);
echo(LatticeCellSizeSi / 8);
//Carbon (graphite) [c]
AtomicRadiusC = 0.7;
LatticeCellSizeC = 3.65;
cellLenA = 2.464;
cellLenB = cellLenA;
cellLenC = 6.711;
cellAngleA = 90;
cellAngleB = cellAngleA;
cellAngleC = 120;
LayerSeperationC = 3.364;
ColorC = "Grey";
echo(cellLenA);
echo(cellLenB);
echo(cellLenC);
module bond(p1 = [0,0,0], p2 = [1,1,1], ar1 = 1.0, ar2 = 2.0, c="yellow")
{
cyR = min(ar1,ar2) / 5.0;
dX = p1.x - p2.x;
dY = p1.y - p2.y;
dZ = p1.z - p2.z;
dist = norm([dX, dY, dZ]);
cyC = [p1.x-dX/2, p1.y-dY/2, p1.z-dZ/2];
beta = acos(dZ/dist); // inclination angle
gamma = atan2(dY,dX); // azimuthal angle
rot = [0, beta, gamma];
translate(v=cyC)
rotate(a = rot)
color(c)
cylinder(h=dist, r=cyR, center=true);
};
module bondPair(d=0.0, ar=1.0, c="Black") {
axD = pow(d,1/3);
p1 = [+axD,-axD,-axD];
p2 = [-axD,+axD,+axD];
translate(p1) {
color(c) sphere(r=ar);
};
translate(p2) {
color(c) sphere(r=ar);
}
bond(p1, p2, ar, ar);
};
module hexagonalClosePacked(dst = [1.0, 1.0, 1.0], ar=1.0, c="Black") {
//center
p1 = [0, 0, 0];
color(c) sphere(r=ar);
//Three 120 degrees around center
baseAg = 30;
ag = [baseAg, baseAg + 120, baseAg + 240];
points =[ [cos(ag.x)*dst.x,sin(ag.x)*dst.x,0], [cos(ag.y)*dst.y,sin(ag.y)*dst.y,0],[cos(ag.z)*dst.z,sin(ag.z)*dst.z,0] ];
for (p2 = points)
{
translate(p2)
color(c)
sphere(r=ar);
bond(p1 = p1, p2 = p2, ar1 = ar, ar2 = ar);
}
};
module fccDiamond(ar=1.0, unitCell=2.0, fccOffset=0.25, c="Blue") {
//lattice 8 vertices
huc = unitCell / 2.0;
od = fccOffset * unitCell;
//interstitial
interstitial = [
[+od, +od, +od],
[+od, -od, -od],
[-od, +od, -od],
[-od, -od, +od]
];
//corners
corners = [
[+huc, +huc, +huc],
[+huc, -huc, -huc],
[-huc, +huc, -huc],
[-huc, -huc, +huc]
];
//face centered
fcc = [
[+huc, 0, 0],
[-huc, 0, 0],
[0, +huc, 0],
[0, -huc, 0],
[0, 0, +huc],
[0, 0, -huc]
];
for(p = corners)
translate(p)
color(c)
sphere(r=ar);
for (p = fcc)
translate(p)
color(c)
sphere(r=ar);
for (p = interstitial)
{
translate(p)
color(c)
sphere(r=ar);
}
bonds = [
[ interstitial[0], corners[0]],
[ interstitial[0], fcc[0]],
[ interstitial[0], fcc[2]],
[ interstitial[0], fcc[4]],
[ interstitial[1], corners[1]],
[ interstitial[1], fcc[0]],
[ interstitial[1], fcc[3]],
[ interstitial[1], fcc[5]],
[ interstitial[2], corners[2]],
[ interstitial[2], fcc[1]],
[ interstitial[2], fcc[2]],
[ interstitial[2], fcc[5]],
[ interstitial[3], corners[3]],
[ interstitial[3], fcc[1]],
[ interstitial[3], fcc[3]],
[ interstitial[3], fcc[4]]
];
for(b = bonds)
bond(b.x, b.y, ar, ar);
};
module SiCell(x = 1.0, y = 1.0, z = 1.0) {
//Si cell
translate([+LatticeCellSizeSi * x, +LatticeCellSizeSi * y, +LatticeCellSizeSi * z]) fccDiamond(AtomicRadiusSi, LatticeCellSizeSi, fccOffset, ColorSi);
};
module SiN2Cell(x = 1.0, y = 1.0, z = 1.0) {
n2Offset = LatticeCellSizeSi / 8;
//N2 Pair
translate([+LatticeCellSizeSi * x - n2Offset, +LatticeCellSizeSi * y + n2Offset, +LatticeCellSizeSi * z + n2Offset]) bondPair(BondPairN2, AtomicRadiusN2, ColorN2);
//Si cell
SiCell(x, y, z);
};
module GraphiteCell(xyz = [1.0, 1.0, 1.0]) {
//Graphite cell
loc = [
(cellLenA * xyz.x * cos(30) * 2),
((cellLenB * sin(30)) + cellLenC) * xyz.y,
xyz.z];
translate(loc) hexagonalClosePacked([cellLenA, cellLenB, cellLenC], AtomicRadiusC, ColorC);
};
//graphite layer
siOffset = 3 * LatticeCellSizeSi / 8;
rotate([0, 0, 45])
translate([0, -siOffset, 0])
for (x = [-3:1:3])
for (y = [-1:1:2])
{
offset = (y % 2 == 0) ? 0.0 : 0.5;
GraphiteCell([x + offset, y, LayerSeperationC * 0.5 + LatticeCellSizeSi * 1.5]);
}
//top layer has N2
xyPlane = [-2,-1,0,+1,+2];
for (x = xyPlane)
for (y = xyPlane)
SiN2Cell( x, y, +1);
//below is just the silcon waffer
*for (x = xyPlane)
for (y = xyPlane)
for (z =[-1,0])
SiCell( x, y, z);
segments=10;
rows=2;
minkowski() {
union() {
for(i=[0:segments]) {
for(j=[0:rows]) {
polyhedron(
points=[
[
sin(360/segments*i)*sqrt(rows-j+1),
cos(360/segments*i)*sqrt(rows-j+1),
j
],
[
sin(360/segments*(i+1))*sqrt(rows-j+1),
cos(360/segments*(i+1))*sqrt(rows-j+1),
j
],
[
sin(360/segments*(i+0.5))*sqrt(rows-j),
cos(360/segments*(i+0.5))*sqrt(rows-j),
j+1
]],triangles=[[0,1,2]]);
}
}
}
cube([0.1,0.1,0.1],center=true);
}
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
//
// Context: https://github.com/openscad/openscad/pull/3636
//
// openscad --enable=fast-union cube-with-half-spheres-dents.scad -o cube-with-half-spheres-dents.stl
// Runs in 1min8sec with the feature, 4min25sec without (almost 4x speedup)
N = 5;
overlap=true
difference() {
translate([-0.5, -0.5, -0.5]) cube([N, N, 0.5]);
// Explicit union here, as difference isn't optimized yet (only union is).
union() {
for (i=[0:N-1], j=[0:N-1])
translate([i, j, 0])
sphere(d=(overlap ? 1.1 : 0.9), $fn=50);
}
}
// translate([1, 0, 0])
// union() {
// cube(1);
// cube(2);
// }
// cube(3);
group() group() cube();
// translate([1, 0, 0]) translate([1, 1, 0]) cube();
// translate([0.5, 0, 0])
//*
$fn=20;
// translate([1, 0, 0]) {
// cube(1, center=true);
// translate([0.1, 0, 0])
// cube(1.2, center=true);
// }
module A() {
sphere(1);
translate([1, 0, 0]) {
cube(1, center=true);
translate([0.1, 0, 0])
cube(1.2, center=true);
}
}
for (i=[0:3])
translate([i*2, 0, 0]) A();
//*/
// translate([1, 0, 0]) { cube(); sphere(); }
// translate([1, 0, 0]) { cube(); sphere(); }
#!/bin/bash
#
# Creates JSON parameter sets that can be used to create variations of benchmark tests.
# Takes a list of OpenSCAD script snippets that each declare a variable's possible values,
# and generates the JSON param sets that describes the cross product of these values.
#
# Usage:
# ./gen_param_sets 'N=[2,10]' '$fn=[20,100]' > scalemail.json
# ./gen_param_sets 'dishFn=[0:2:10]' 'smoothFn=[10,100,200]'
# ./gen_param_sets 'Part=["Head", "Body"]' '$fn=concat(10, [100:100:1000])'
#
set -euo pipefail
OPENSCAD=${OPENSCAD:-$PWD/../openscad1/build/OpenSCAD.app/Contents/MacOS/OpenSCAD}
function join_by {
local IFS="$1"
shift
echo "$*"
}
vars=( "$@" )
varnames=()
varpairs=()
for var in "${vars[@]}" ; do
varname="$( echo "$var" | sed -E 's/(.*)=.*/\1/' )"
varnames+=( "$varname" )
varpairs+=( "[\"$varname\", $varname]" )
done
script='
function join(list, sep, _i=0, _acc="") =
_i >= len(list)
? _acc
: join(list, sep, _i + 1,
str(_i == 0 ? "" : str(_acc, sep), list[_i]));
function fmt_json_string(v) =
str("\"", v, "\"");
//function fmt_json_value(v) =
// is_string(v) ? str("\"", v, "\"") : str(v);
function fmt_json_object(pairs) =
str("{",
join([
for (pair=pairs)
str(fmt_json_string(pair[0]), ": ", pair[1])
], ","),
"}");
function fmt_json_array(list) =
str("[", join(list, ", "), "]");
echo(
fmt_json_object([
["fileFormatVersion", fmt_json_string(1)],
["parameterSets", fmt_json_object([
for ('"$( join_by , "${vars[@]}" )"')
let(vars=['"$( join_by , "${varpairs[@]}" )"'])
let(name=join([for (v=vars) str(v[0], "=", v[1])], " "))
[name, fmt_json_object([for (v=vars) [v[0], fmt_json_string(v[1])]])]
])]
])
);
'
# echo "$script" >&2
echo "$script" | \
$OPENSCAD - -o - --export-format csg 2>&1 | \
sed -E 's/^ECHO: "(.*)"$/\1/' | \
python3 -m json.tool
#!/bin/bash
# Copyright 2021 Google LLC.
# SPDX-License-Identifier: Apache-2.00
set -euo pipefail
LIBS_DIR=${LIBS_DIR:-$PWD/libs}
github_repos=(
adrianschlatter/threadlib
CarlosGS/Cyclone-PCB-Factory
clothbot/ClothBotCreations
hyperair/projector-mount
JustinSDK/dotSCAD
nophead/NopSCADlib
ochafik/list-comprehension-demos
ochafik/miscellaneous-scad
ochafik/Round-Anything
ochafik/scad-utils
rcolyer/threads-scad
revarbat/BOSL2
SebiTimeWaster/Chamfers-for-OpenSCAD
MoffittLab/OpenSCAD
MisterHW/IoP-satellite
)
symlinks=(
# "github.com/rcolyer/threads-scad/threads.scad"
"github.com/MoffittLab/OpenSCAD/OpenSCADModules/threads.scad"
"github.com/MisterHW/IoP-satellite/OpenSCAD bottle threads/thread_profile.scad"
)
echo "# Checking out libraries"
mkdir -p "$LIBS_DIR"
cd "$LIBS_DIR"
for github_repo in "${github_repos[@]}" ; do
dir="github.com/$github_repo"
if [[ -d "$dir" ]]; then
( cd "$dir" ; git pull )
else
mkdir -p "$( dirname "$dir" )"
git clone --depth=1 "https://github.com/$github_repo" "$dir" || true
fi
ln -sf "$dir" "$( basename "$github_repo" )"
done
for symlink in "${symlinks[@]}" ; do
ln -sf "$symlink" . || true
done
cube();
scale([1, 0 , 0]) cube();
//cube();
for (i=[0:10])
//translate([i*1.2, 0, 0])
for (j=[0:10])
translate([i*1.2, j*1.2, 0])
sphere(1, $fn=30);
/*
minkowski() {
hull() {
cube();
translate([1, 1, 1]) cube();
}
sphere(r=0.2, $fn=100);
}
//*/
include <BOSL2/std.scad>
z=6;
bottom_half(z=z)
import("maze-manifold.stl");
//import("maze-fastcsg.stl");
{
"fileFormatVersion": "1",
"parameterSets": {
"n=2": {
"n": "2"
},
"n=10": {
"n": "10"
}
}
}
n = 10;
rad = 0.4;
module rod(a, b, r, $fn=20) {
//translate(a) sphere(r=r, $fn=$fn);
//translate(b) sphere(r=r, $fn=$fn);
dir = b-a;
h = norm(dir);
if(dir[0] == 0 && dir[1] == 0) {
// no transformation necessary
if (a[2] > b[2]) {
translate(b) {
cylinder(r=r, h=h, $fn = $fn);
}
} else {
translate(a) {
cylinder(r=r, h=h, $fn = $fn);
}
}
}
else {
w = dir / h;
u0 = cross(w, [0,0,1]);
u = u0 / norm(u0);
v0 = cross(w, u);
v = v0 / norm(v0);
multmatrix(m=[[u[0], v[0], w[0], a[0]],
[u[1], v[1], w[1], a[1]],
[u[2], v[2], w[2], a[2]],
[0, 0, 0, 1]])
cylinder(r=r, h=h, $fn = $fn);
}
}
module ball(x, r, $fn=20) {
translate(x) {
sphere(r=r, $fn = $fn);
}
}
difference() {
cube((n+1)*[1,1,1]);
rod([1,1,1],[0,1,1],0.4, $fn=20);
rod(n*[1,1,1],[n+1,n,n],0.4, $fn=20);
rod([1,1,1],[1,1,2],0.4);
rod([1,1,2],[2,1,2],0.4);
rod([2,1,2],[3,1,2],0.4);
rod([3,1,2],[4,1,2],0.4);
rod([4,1,2],[4,2,2],0.4);
rod([4,2,2],[4,2,3],0.4);
rod([4,1,3],[4,2,3],0.4);
rod([3,1,3],[4,1,3],0.4);
rod([2,1,3],[3,1,3],0.4);
rod([2,1,3],[2,2,3],0.4);
rod([2,2,3],[2,2,4],0.4);
rod([2,2,4],[2,2,5],0.4);
rod([2,1,5],[2,2,5],0.4);
rod([1,1,5],[2,1,5],0.4);
rod([1,1,5],[1,1,6],0.4);
rod([1,1,6],[2,1,6],0.4);
rod([2,2,5],[2,2,6],0.4);
rod([2,2,6],[2,2,7],0.4);
rod([1,2,7],[2,2,7],0.4);
rod([2,2,7],[3,2,7],0.4);
rod([3,2,6],[3,2,7],0.4);
rod([3,2,6],[3,3,6],0.4);
rod([3,3,6],[4,3,6],0.4);
rod([4,3,6],[4,3,7],0.4);
rod([3,3,7],[4,3,7],0.4);
rod([3,3,7],[3,3,8],0.4);
rod([2,3,8],[3,3,8],0.4);
rod([2,3,7],[2,3,8],0.4);
rod([1,3,7],[2,3,7],0.4);
rod([1,3,7],[1,3,8],0.4);
rod([2,2,8],[2,3,8],0.4);
rod([2,1,7],[2,2,7],0.4);
rod([3,3,7],[3,4,7],0.4);
rod([3,4,7],[3,5,7],0.4);
rod([3,4,7],[3,4,8],0.4);
rod([3,5,6],[3,5,7],0.4);
rod([3,4,6],[3,5,6],0.4);
rod([3,4,6],[4,4,6],0.4);
rod([4,4,6],[4,5,6],0.4);
rod([4,4,6],[5,4,6],0.4);
rod([5,4,6],[5,5,6],0.4);
rod([4,5,6],[4,5,7],0.4);
rod([2,5,7],[3,5,7],0.4);
rod([2,5,7],[2,6,7],0.4);
rod([2,6,7],[3,6,7],0.4);
rod([3,6,7],[3,7,7],0.4);
rod([3,7,7],[3,7,8],0.4);
rod([3,6,8],[3,7,8],0.4);
rod([3,6,8],[4,6,8],0.4);
rod([3,6,8],[3,6,9],0.4);
rod([3,5,9],[3,6,9],0.4);
rod([3,5,9],[3,5,10],0.4);
rod([2,5,10],[3,5,10],0.4);
rod([3,5,10],[3,6,10],0.4);
rod([2,6,10],[3,6,10],0.4);
rod([2,6,9],[2,6,10],0.4);
rod([2,6,8],[2,6,9],0.4);
rod([3,5,8],[3,6,8],0.4);
rod([2,4,8],[3,4,8],0.4);
rod([2,4,8],[2,5,8],0.4);
rod([2,5,9],[2,6,9],0.4);
rod([1,5,9],[2,5,9],0.4);
rod([1,4,9],[1,5,9],0.4);
rod([1,4,9],[1,4,10],0.4);
rod([1,4,10],[1,5,10],0.4);
rod([1,5,10],[1,6,10],0.4);
rod([2,6,10],[2,7,10],0.4);
rod([2,7,9],[2,7,10],0.4);
rod([2,7,9],[2,8,9],0.4);
rod([1,8,9],[2,8,9],0.4);
rod([2,7,10],[2,8,10],0.4);
rod([1,8,10],[2,8,10],0.4);
rod([1,8,8],[1,8,9],0.4);
rod([1,7,8],[1,8,8],0.4);
rod([1,6,8],[1,7,8],0.4);
rod([2,6,8],[2,7,8],0.4);
rod([2,7,8],[2,8,8],0.4);
rod([3,7,8],[3,8,8],0.4);
rod([3,8,8],[3,9,8],0.4);
rod([3,9,8],[4,9,8],0.4);
rod([4,9,8],[4,10,8],0.4);
rod([4,10,8],[5,10,8],0.4);
rod([5,10,8],[6,10,8],0.4);
rod([6,10,7],[6,10,8],0.4);
rod([6,9,7],[6,10,7],0.4);
rod([5,9,7],[6,9,7],0.4);
rod([5,8,7],[5,9,7],0.4);
rod([5,8,7],[5,8,8],0.4);
rod([5,8,8],[5,9,8],0.4);
rod([4,9,7],[5,9,7],0.4);
rod([3,9,7],[4,9,7],0.4);
rod([3,9,6],[3,9,7],0.4);
rod([2,9,6],[3,9,6],0.4);
rod([2,9,6],[2,10,6],0.4);
rod([2,10,6],[3,10,6],0.4);
rod([3,10,6],[3,10,7],0.4);
rod([3,10,7],[3,10,8],0.4);
rod([3,10,8],[3,10,9],0.4);
rod([2,10,9],[3,10,9],0.4);
rod([2,9,9],[2,10,9],0.4);
rod([2,9,9],[3,9,9],0.4);
rod([3,10,9],[3,10,10],0.4);
rod([2,10,10],[3,10,10],0.4);
rod([2,9,10],[2,10,10],0.4);
rod([1,9,9],[2,9,9],0.4);
rod([1,9,8],[1,9,9],0.4);
rod([1,9,7],[1,9,8],0.4);
rod([1,9,7],[1,10,7],0.4);
rod([1,10,7],[1,10,8],0.4);
rod([1,10,8],[2,10,8],0.4);
rod([3,10,7],[4,10,7],0.4);
rod([4,8,7],[4,9,7],0.4);
rod([4,7,7],[4,8,7],0.4);
rod([4,6,7],[4,7,7],0.4);
rod([4,6,7],[5,6,7],0.4);
rod([5,6,7],[5,7,7],0.4);
rod([5,7,7],[5,7,8],0.4);
rod([4,8,8],[5,8,8],0.4);
rod([4,8,8],[4,8,9],0.4);
rod([4,8,9],[4,9,9],0.4);
rod([4,9,9],[4,10,9],0.4);
rod([4,9,9],[4,9,10],0.4);
rod([4,9,10],[5,9,10],0.4);
rod([5,9,10],[5,10,10],0.4);
rod([4,10,10],[5,10,10],0.4);
rod([4,9,6],[4,9,7],0.4);
rod([3,8,6],[3,9,6],0.4);
rod([3,7,6],[3,8,6],0.4);
rod([3,7,5],[3,7,6],0.4);
rod([3,7,5],[4,7,5],0.4);
rod([3,7,4],[3,7,5],0.4);
rod([2,7,4],[3,7,4],0.4);
rod([1,7,4],[2,7,4],0.4);
rod([1,7,3],[1,7,4],0.4);
rod([1,7,3],[1,8,3],0.4);
rod([1,6,3],[1,7,3],0.4);
rod([1,5,3],[1,6,3],0.4);
rod([1,4,3],[1,5,3],0.4);
rod([1,4,2],[1,4,3],0.4);
rod([1,3,2],[1,4,2],0.4);
rod([1,3,2],[2,3,2],0.4);
rod([1,3,1],[1,3,2],0.4);
rod([1,2,1],[1,3,1],0.4);
rod([1,3,1],[1,4,1],0.4);
rod([1,2,1],[2,2,1],0.4);
rod([2,2,1],[2,3,1],0.4);
rod([2,3,1],[2,4,1],0.4);
rod([2,4,1],[2,4,2],0.4);
rod([1,4,2],[1,5,2],0.4);
rod([1,5,1],[1,5,2],0.4);
rod([1,5,1],[2,5,1],0.4);
rod([2,5,1],[2,6,1],0.4);
rod([2,6,1],[2,6,2],0.4);
rod([2,6,2],[3,6,2],0.4);
rod([3,6,2],[4,6,2],0.4);
rod([4,5,2],[4,6,2],0.4);
rod([4,4,2],[4,5,2],0.4);
rod([4,3,2],[4,4,2],0.4);
rod([4,3,2],[4,3,3],0.4);
rod([4,2,3],[4,2,4],0.4);
rod([4,2,4],[4,2,5],0.4);
rod([4,2,5],[5,2,5],0.4);
rod([5,2,5],[6,2,5],0.4);
rod([6,2,5],[6,2,6],0.4);
rod([6,1,6],[6,2,6],0.4);
rod([6,1,6],[7,1,6],0.4);
rod([7,1,6],[7,2,6],0.4);
rod([7,2,6],[7,3,6],0.4);
rod([7,3,6],[7,3,7],0.4);
rod([7,2,7],[7,3,7],0.4);
rod([6,2,7],[7,2,7],0.4);
rod([5,2,7],[6,2,7],0.4);
rod([5,2,7],[5,3,7],0.4);
rod([5,3,7],[5,3,8],0.4);
rod([5,3,7],[6,3,7],0.4);
rod([6,3,7],[6,3,8],0.4);
rod([6,3,8],[6,4,8],0.4);
rod([6,4,8],[6,5,8],0.4);
rod([6,5,8],[7,5,8],0.4);
rod([7,5,8],[7,5,9],0.4);
rod([7,4,9],[7,5,9],0.4);
rod([6,4,9],[7,4,9],0.4);
rod([6,3,9],[6,4,9],0.4);
rod([7,4,8],[7,4,9],0.4);
rod([7,5,9],[8,5,9],0.4);
rod([8,5,9],[9,5,9],0.4);
rod([9,5,9],[10,5,9],0.4);
rod([10,5,9],[10,6,9],0.4);
rod([10,6,9],[10,7,9],0.4);
rod([9,7,9],[10,7,9],0.4);
rod([9,7,9],[9,7,10],0.4);
rod([9,7,10],[9,8,10],0.4);
rod([8,8,10],[9,8,10],0.4);
rod([8,7,10],[8,8,10],0.4);
rod([8,8,10],[8,9,10],0.4);
rod([8,9,10],[8,10,10],0.4);
rod([8,10,9],[8,10,10],0.4);
rod([7,10,9],[8,10,9],0.4);
rod([7,10,9],[7,10,10],0.4);
rod([6,10,10],[7,10,10],0.4);
rod([6,10,9],[6,10,10],0.4);
rod([6,9,9],[6,10,9],0.4);
rod([6,9,9],[6,9,10],0.4);
rod([6,8,10],[6,9,10],0.4);
rod([2,8,9],[3,8,9],0.4);
rod([3,8,9],[3,8,10],0.4);
rod([2,9,8],[2,9,9],0.4);
rod([1,10,8],[1,10,9],0.4);
rod([1,7,9],[1,8,9],0.4);
rod([3,6,9],[3,7,9],0.4);
rod([3,8,7],[3,8,8],0.4);
rod([6,9,7],[6,9,8],0.4);
rod([6,9,6],[6,9,7],0.4);
rod([5,9,6],[6,9,6],0.4);
rod([6,9,5],[6,9,6],0.4);
rod([6,8,6],[6,9,6],0.4);
rod([6,8,5],[6,8,6],0.4);
rod([5,8,6],[6,8,6],0.4);
rod([5,8,5],[5,8,6],0.4);
rod([5,7,5],[5,8,5],0.4);
rod([5,8,4],[5,8,5],0.4);
rod([5,8,3],[5,8,4],0.4);
rod([5,8,3],[5,9,3],0.4);
rod([5,9,2],[5,9,3],0.4);
rod([5,9,2],[5,10,2],0.4);
rod([5,10,2],[6,10,2],0.4);
rod([6,10,1],[6,10,2],0.4);
rod([6,10,1],[7,10,1],0.4);
rod([7,10,1],[7,10,2],0.4);
rod([7,10,2],[7,10,3],0.4);
rod([7,10,2],[8,10,2],0.4);
rod([8,10,2],[8,10,3],0.4);
rod([8,10,1],[8,10,2],0.4);
rod([7,9,1],[7,10,1],0.4);
rod([6,9,1],[6,10,1],0.4);
rod([5,9,1],[6,9,1],0.4);
rod([5,9,1],[5,10,1],0.4);
rod([6,8,1],[6,9,1],0.4);
rod([6,7,1],[6,8,1],0.4);
rod([6,7,1],[6,7,2],0.4);
rod([6,6,2],[6,7,2],0.4);
rod([5,6,2],[6,6,2],0.4);
rod([5,6,2],[5,7,2],0.4);
rod([5,7,2],[5,8,2],0.4);
rod([5,9,3],[6,9,3],0.4);
rod([6,8,3],[6,9,3],0.4);
rod([6,7,3],[6,8,3],0.4);
rod([6,6,3],[6,7,3],0.4);
rod([6,6,3],[6,6,4],0.4);
rod([5,6,4],[6,6,4],0.4);
rod([5,6,3],[5,6,4],0.4);
rod([5,6,1],[5,6,2],0.4);
rod([5,5,2],[5,6,2],0.4);
rod([5,5,2],[6,5,2],0.4);
rod([6,7,2],[6,8,2],0.4);
rod([6,8,2],[6,9,2],0.4);
rod([7,9,2],[7,10,2],0.4);
rod([6,10,2],[6,10,3],0.4);
rod([4,9,3],[5,9,3],0.4);
rod([3,9,3],[4,9,3],0.4);
rod([3,9,3],[3,10,3],0.4);
rod([2,10,3],[3,10,3],0.4);
rod([2,10,2],[2,10,3],0.4);
rod([2,10,2],[3,10,2],0.4);
rod([3,9,2],[3,10,2],0.4);
rod([3,9,1],[3,9,2],0.4);
rod([3,9,1],[4,9,1],0.4);
rod([3,8,2],[3,9,2],0.4);
rod([3,7,2],[3,8,2],0.4);
rod([3,7,2],[3,7,3],0.4);
rod([3,6,1],[3,6,2],0.4);
rod([2,3,1],[3,3,1],0.4);
rod([3,3,1],[4,3,1],0.4);
rod([4,3,1],[4,4,1],0.4);
rod([3,4,1],[4,4,1],0.4);
rod([3,4,1],[3,4,2],0.4);
rod([3,3,2],[4,3,2],0.4);
rod([2,4,2],[2,4,3],0.4);
rod([2,4,2],[2,5,2],0.4);
rod([2,5,2],[3,5,2],0.4);
rod([3,7,2],[4,7,2],0.4);
rod([4,7,2],[4,7,3],0.4);
rod([4,6,3],[4,7,3],0.4);
rod([4,5,3],[4,6,3],0.4);
rod([4,4,3],[4,5,3],0.4);
rod([4,4,3],[4,4,4],0.4);
rod([4,4,4],[4,4,5],0.4);
rod([4,4,5],[5,4,5],0.4);
rod([5,4,4],[5,4,5],0.4);
rod([2,4,6],[3,4,6],0.4);
rod([2,4,6],[2,4,7],0.4);
rod([4,8,9],[5,8,9],0.4);
rod([5,7,9],[5,8,9],0.4);
rod([5,8,9],[5,9,9],0.4);
rod([5,8,10],[5,9,10],0.4);
rod([5,9,9],[5,10,9],0.4);
rod([5,10,7],[6,10,7],0.4);
rod([1,9,10],[2,9,10],0.4);
rod([1,10,9],[1,10,10],0.4);
rod([2,9,10],[3,9,10],0.4);
rod([3,6,9],[4,6,9],0.4);
rod([1,6,9],[1,7,9],0.4);
rod([2,4,9],[2,5,9],0.4);
rod([2,3,9],[2,4,9],0.4);
rod([1,3,8],[1,3,9],0.4);
rod([1,3,9],[1,3,10],0.4);
rod([1,3,10],[2,3,10],0.4);
rod([2,2,10],[2,3,10],0.4);
rod([2,2,9],[2,2,10],0.4);
rod([1,2,9],[2,2,9],0.4);
rod([1,2,10],[2,2,10],0.4);
rod([1,1,10],[1,2,10],0.4);
rod([1,1,9],[1,1,10],0.4);
rod([1,1,10],[2,1,10],0.4);
rod([3,5,8],[4,5,8],0.4);
rod([3,6,6],[3,6,7],0.4);
rod([4,4,7],[4,5,7],0.4);
rod([2,5,6],[3,5,6],0.4);
rod([2,5,6],[2,6,6],0.4);
rod([2,6,5],[2,6,6],0.4);
rod([2,6,5],[3,6,5],0.4);
rod([1,6,6],[2,6,6],0.4);
rod([1,6,5],[1,6,6],0.4);
rod([1,6,5],[1,7,5],0.4);
rod([1,7,5],[1,8,5],0.4);
rod([1,8,5],[1,9,5],0.4);
rod([1,9,5],[1,9,6],0.4);
rod([1,9,6],[1,10,6],0.4);
rod([1,10,5],[1,10,6],0.4);
rod([2,9,6],[2,9,7],0.4);
rod([2,8,7],[2,9,7],0.4);
rod([5,7,10],[5,8,10],0.4);
rod([4,7,10],[5,7,10],0.4);
rod([4,7,9],[4,7,10],0.4);
rod([4,7,8],[4,7,9],0.4);
rod([4,8,9],[4,8,10],0.4);
rod([5,7,9],[6,7,9],0.4);
rod([6,7,9],[7,7,9],0.4);
rod([7,7,9],[8,7,9],0.4);
rod([7,7,9],[7,7,10],0.4);
rod([7,7,10],[7,8,10],0.4);
rod([6,8,9],[6,8,10],0.4);
rod([6,8,9],[7,8,9],0.4);
rod([7,8,10],[7,9,10],0.4);
rod([7,8,9],[8,8,9],0.4);
rod([8,8,9],[8,9,9],0.4);
rod([8,9,9],[9,9,9],0.4);
rod([8,9,10],[9,9,10],0.4);
rod([9,8,9],[9,8,10],0.4);
rod([9,8,9],[10,8,9],0.4);
rod([9,9,9],[10,9,9],0.4);
rod([10,9,9],[10,9,10],0.4);
rod([10,9,10],[10,10,10],0.4);
rod([8,9,8],[8,9,9],0.4);
rod([8,9,8],[8,10,8],0.4);
rod([8,10,10],[9,10,10],0.4);
rod([9,9,9],[9,10,9],0.4);
rod([7,8,8],[7,8,9],0.4);
rod([6,8,8],[7,8,8],0.4);
rod([7,9,9],[7,9,10],0.4);
rod([6,7,10],[7,7,10],0.4);
rod([3,7,9],[3,7,10],0.4);
rod([4,7,6],[4,7,7],0.4);
rod([2,7,6],[3,7,6],0.4);
rod([1,7,6],[2,7,6],0.4);
rod([2,7,6],[2,7,7],0.4);
rod([6,9,7],[7,9,7],0.4);
rod([7,8,7],[7,9,7],0.4);
rod([7,7,7],[7,8,7],0.4);
rod([7,6,7],[7,7,7],0.4);
rod([7,6,6],[7,6,7],0.4);
rod([7,6,7],[7,6,8],0.4);
rod([7,6,8],[7,6,9],0.4);
rod([5,7,8],[6,7,8],0.4);
rod([6,6,8],[6,7,8],0.4);
rod([7,5,7],[7,5,8],0.4);
rod([7,6,7],[8,6,7],0.4);
rod([8,6,7],[9,6,7],0.4);
rod([9,5,7],[9,6,7],0.4);
rod([9,4,7],[9,5,7],0.4);
rod([8,4,7],[9,4,7],0.4);
rod([8,4,6],[8,4,7],0.4);
rod([8,4,5],[8,4,6],0.4);
rod([7,4,5],[8,4,5],0.4);
rod([7,4,5],[7,4,6],0.4);
rod([7,4,6],[7,5,6],0.4);
rod([8,4,6],[9,4,6],0.4);
rod([9,4,6],[9,5,6],0.4);
rod([8,5,6],[9,5,6],0.4);
rod([8,5,6],[8,6,6],0.4);
rod([8,4,7],[8,5,7],0.4);
rod([8,5,5],[8,5,6],0.4);
rod([8,5,5],[9,5,5],0.4);
rod([8,4,5],[9,4,5],0.4);
rod([9,4,4],[9,4,5],0.4);
rod([9,3,4],[9,4,4],0.4);
rod([9,2,4],[9,3,4],0.4);
rod([9,1,4],[9,2,4],0.4);
rod([9,3,4],[9,3,5],0.4);
rod([9,4,4],[10,4,4],0.4);
rod([10,4,4],[10,4,5],0.4);
rod([10,4,5],[10,5,5],0.4);
rod([10,4,5],[10,4,6],0.4);
rod([10,3,6],[10,4,6],0.4);
rod([10,3,5],[10,3,6],0.4);
rod([10,3,4],[10,3,5],0.4);
rod([10,3,3],[10,3,4],0.4);
rod([10,3,2],[10,3,3],0.4);
rod([10,3,2],[10,4,2],0.4);
rod([10,4,2],[10,4,3],0.4);
rod([9,4,3],[10,4,3],0.4);
rod([9,4,2],[9,4,3],0.4);
rod([9,3,2],[9,4,2],0.4);
rod([9,3,2],[9,3,3],0.4);
rod([10,4,3],[10,5,3],0.4);
rod([9,5,3],[10,5,3],0.4);
rod([9,5,3],[9,5,4],0.4);
rod([9,5,4],[10,5,4],0.4);
rod([8,5,4],[9,5,4],0.4);
rod([8,5,3],[8,5,4],0.4);
rod([8,5,3],[8,6,3],0.4);
rod([8,4,4],[8,5,4],0.4);
rod([7,5,4],[8,5,4],0.4);
rod([7,4,4],[7,5,4],0.4);
rod([7,5,4],[7,6,4],0.4);
rod([6,6,4],[6,6,5],0.4);
rod([6,6,5],[6,7,5],0.4);
rod([6,7,5],[6,7,6],0.4);
rod([5,7,6],[6,7,6],0.4);
rod([4,7,6],[4,8,6],0.4);
rod([3,8,5],[3,8,6],0.4);
rod([2,8,5],[3,8,5],0.4);
rod([2,8,4],[2,8,5],0.4);
rod([2,7,4],[2,7,5],0.4);
rod([1,8,4],[1,8,5],0.4);
rod([1,8,4],[1,9,4],0.4);
rod([1,9,4],[1,10,4],0.4);
rod([1,10,3],[1,10,4],0.4);
rod([1,10,4],[2,10,4],0.4);
rod([2,9,4],[2,10,4],0.4);
rod([2,9,3],[2,9,4],0.4);
rod([1,9,3],[2,9,3],0.4);
rod([1,7,3],[2,7,3],0.4);
rod([3,6,4],[3,7,4],0.4);
rod([2,8,5],[2,8,6],0.4);
rod([1,8,5],[1,8,6],0.4);
rod([3,8,5],[3,9,5],0.4);
rod([3,9,4],[3,9,5],0.4);
rod([4,8,3],[4,9,3],0.4);
rod([4,9,3],[4,9,4],0.4);
rod([4,9,4],[4,10,4],0.4);
rod([4,10,4],[5,10,4],0.4);
rod([5,10,3],[5,10,4],0.4);
rod([4,9,2],[5,9,2],0.4);
rod([4,7,3],[4,7,4],0.4);
rod([3,7,4],[3,8,4],0.4);
rod([3,8,5],[4,8,5],0.4);
rod([4,8,5],[4,9,5],0.4);
rod([2,9,5],[3,9,5],0.4);
rod([4,9,5],[4,10,5],0.4);
rod([4,10,5],[5,10,5],0.4);
rod([5,10,5],[5,10,6],0.4);
rod([3,9,5],[3,10,5],0.4);
rod([1,8,7],[1,9,7],0.4);
rod([1,7,6],[1,7,7],0.4);
rod([6,8,5],[7,8,5],0.4);
rod([7,8,4],[7,8,5],0.4);
rod([6,8,4],[7,8,4],0.4);
rod([6,8,3],[7,8,3],0.4);
rod([7,7,3],[7,8,3],0.4);
rod([7,7,2],[7,7,3],0.4);
rod([7,7,2],[7,8,2],0.4);
rod([7,6,2],[7,7,2],0.4);
rod([7,6,1],[7,6,2],0.4);
rod([7,6,1],[8,6,1],0.4);
rod([6,6,1],[7,6,1],0.4);
rod([6,5,1],[6,6,1],0.4);
rod([6,4,1],[6,5,1],0.4);
rod([5,4,1],[6,4,1],0.4);
rod([5,4,1],[5,5,1],0.4);
rod([4,5,1],[5,5,1],0.4);
rod([3,2,1],[3,3,1],0.4);
rod([3,2,1],[4,2,1],0.4);
rod([3,2,1],[3,2,2],0.4);
rod([1,1,2],[1,1,3],0.4);
rod([1,1,3],[1,1,4],0.4);
rod([1,1,4],[2,1,4],0.4);
rod([2,1,4],[3,1,4],0.4);
rod([3,1,4],[3,2,4],0.4);
rod([3,2,4],[3,3,4],0.4);
rod([3,3,4],[3,4,4],0.4);
rod([5,4,6],[5,4,7],0.4);
rod([5,3,8],[5,4,8],0.4);
rod([5,4,7],[5,5,7],0.4);
rod([5,5,7],[6,5,7],0.4);
rod([6,5,6],[6,5,7],0.4);
rod([6,4,6],[6,5,6],0.4);
rod([6,4,5],[6,4,6],0.4);
rod([5,3,5],[5,4,5],0.4);
rod([5,2,5],[5,2,6],0.4);
rod([5,1,7],[5,2,7],0.4);
rod([5,1,6],[5,1,7],0.4);
rod([5,1,5],[5,2,5],0.4);
rod([4,2,5],[4,2,6],0.4);
rod([6,1,6],[6,1,7],0.4);
rod([6,1,7],[6,1,8],0.4);
rod([5,1,8],[6,1,8],0.4);
rod([4,1,8],[5,1,8],0.4);
rod([3,1,8],[4,1,8],0.4);
rod([3,1,8],[3,1,9],0.4);
rod([3,1,9],[4,1,9],0.4);
rod([4,1,9],[5,1,9],0.4);
rod([4,1,7],[4,1,8],0.4);
rod([4,1,6],[4,1,7],0.4);
rod([4,1,8],[4,2,8],0.4);
rod([4,2,8],[5,2,8],0.4);
rod([5,1,9],[6,1,9],0.4);
rod([6,1,9],[7,1,9],0.4);
rod([6,1,9],[6,1,10],0.4);
rod([6,1,10],[7,1,10],0.4);
rod([7,1,10],[8,1,10],0.4);
rod([8,1,9],[8,1,10],0.4);
rod([8,1,10],[8,2,10],0.4);
rod([8,1,10],[9,1,10],0.4);
rod([9,1,9],[9,1,10],0.4);
rod([9,1,9],[9,2,9],0.4);
rod([8,2,9],[9,2,9],0.4);
rod([8,2,8],[8,2,9],0.4);
rod([7,2,10],[8,2,10],0.4);
rod([7,2,10],[7,3,10],0.4);
rod([7,3,9],[7,3,10],0.4);
rod([7,3,9],[8,3,9],0.4);
rod([7,2,9],[7,3,9],0.4);
rod([9,2,9],[9,3,9],0.4);
rod([8,3,9],[8,3,10],0.4);
rod([8,3,10],[9,3,10],0.4);
rod([9,2,9],[10,2,9],0.4);
rod([10,1,9],[10,2,9],0.4);
rod([10,2,9],[10,2,10],0.4);
rod([10,2,9],[10,3,9],0.4);
rod([10,3,9],[10,4,9],0.4);
rod([10,4,8],[10,4,9],0.4);
rod([10,4,8],[10,5,8],0.4);
rod([10,4,7],[10,4,8],0.4);
rod([10,4,7],[10,5,7],0.4);
rod([10,5,6],[10,5,7],0.4);
rod([10,5,6],[10,6,6],0.4);
rod([10,6,6],[10,7,6],0.4);
rod([9,7,6],[10,7,6],0.4);
rod([9,7,6],[9,8,6],0.4);
rod([8,8,6],[9,8,6],0.4);
rod([8,8,5],[8,8,6],0.4);
rod([8,8,4],[8,8,5],0.4);
rod([8,8,3],[8,8,4],0.4);
rod([8,8,4],[9,8,4],0.4);
rod([9,7,4],[9,8,4],0.4);
rod([9,7,4],[10,7,4],0.4);
rod([10,7,3],[10,7,4],0.4);
rod([10,7,4],[10,7,5],0.4);
rod([9,7,5],[10,7,5],0.4);
rod([8,7,5],[9,7,5],0.4);
rod([8,8,5],[9,8,5],0.4);
rod([8,8,6],[8,8,7],0.4);
rod([7,8,8],[7,9,8],0.4);
rod([6,10,8],[7,10,8],0.4);
rod([7,10,7],[7,10,8],0.4);
rod([7,10,6],[7,10,7],0.4);
rod([6,10,6],[7,10,6],0.4);
rod([4,10,6],[5,10,6],0.4);
rod([5,9,4],[5,10,4],0.4);
rod([5,7,4],[5,8,4],0.4);
rod([5,5,4],[5,6,4],0.4);
rod([5,5,4],[6,5,4],0.4);
rod([4,5,4],[5,5,4],0.4);
rod([3,5,4],[4,5,4],0.4);
rod([3,5,3],[3,5,4],0.4);
rod([2,5,3],[3,5,3],0.4);
rod([5,5,3],[5,5,4],0.4);
rod([5,5,3],[6,5,3],0.4);
rod([6,5,2],[7,5,2],0.4);
rod([7,4,2],[7,5,2],0.4);
rod([7,4,2],[7,4,3],0.4);
rod([7,3,3],[7,4,3],0.4);
rod([7,3,3],[7,3,4],0.4);
rod([7,3,4],[8,3,4],0.4);
rod([8,3,4],[8,3,5],0.4);
rod([8,4,3],[8,4,4],0.4);
rod([8,3,3],[8,4,3],0.4);
rod([8,3,2],[8,3,3],0.4);
rod([9,4,2],[9,5,2],0.4);
rod([8,3,1],[8,3,2],0.4);
rod([8,2,1],[8,3,1],0.4);
rod([8,1,1],[8,2,1],0.4);
rod([8,1,1],[8,1,2],0.4);
rod([7,1,2],[8,1,2],0.4);
rod([7,1,2],[7,1,3],0.4);
rod([8,1,2],[8,2,2],0.4);
rod([8,1,2],[8,1,3],0.4);
rod([8,1,3],[8,1,4],0.4);
rod([7,1,4],[8,1,4],0.4);
rod([7,1,4],[7,1,5],0.4);
rod([6,1,3],[7,1,3],0.4);
rod([5,1,3],[6,1,3],0.4);
rod([5,1,3],[5,2,3],0.4);
rod([5,2,2],[5,2,3],0.4);
rod([5,2,2],[6,2,2],0.4);
rod([6,2,2],[6,2,3],0.4);
rod([6,2,3],[6,3,3],0.4);
rod([7,2,3],[7,3,3],0.4);
rod([7,2,2],[7,2,3],0.4);
rod([8,2,2],[9,2,2],0.4);
rod([9,2,2],[9,2,3],0.4);
rod([9,2,1],[9,2,2],0.4);
rod([9,2,1],[9,3,1],0.4);
rod([9,3,1],[10,3,1],0.4);
rod([10,2,1],[10,3,1],0.4);
rod([10,2,1],[10,2,2],0.4);
rod([8,2,3],[9,2,3],0.4);
rod([7,2,3],[7,2,4],0.4);
rod([7,2,4],[8,2,4],0.4);
rod([8,2,4],[8,2,5],0.4);
rod([8,1,5],[8,2,5],0.4);
rod([8,2,5],[8,2,6],0.4);
rod([8,1,6],[8,2,6],0.4);
rod([8,1,6],[9,1,6],0.4);
rod([9,1,5],[9,1,6],0.4);
rod([9,1,4],[10,1,4],0.4);
rod([10,1,4],[10,1,5],0.4);
rod([10,1,5],[10,2,5],0.4);
rod([9,2,5],[10,2,5],0.4);
rod([9,2,5],[9,2,6],0.4);
rod([9,2,6],[9,3,6],0.4);
rod([8,3,6],[9,3,6],0.4);
rod([9,3,6],[9,3,7],0.4);
rod([9,2,7],[9,3,7],0.4);
rod([9,2,7],[10,2,7],0.4);
rod([10,1,7],[10,2,7],0.4);
rod([9,1,7],[10,1,7],0.4);
rod([10,1,6],[10,1,7],0.4);
rod([10,1,6],[10,2,6],0.4);
rod([8,1,6],[8,1,7],0.4);
rod([10,1,4],[10,2,4],0.4);
rod([10,2,3],[10,2,4],0.4);
rod([10,5,3],[10,6,3],0.4);
rod([10,6,3],[10,6,4],0.4);
rod([10,6,2],[10,6,3],0.4);
rod([9,6,2],[10,6,2],0.4);
rod([9,6,2],[9,7,2],0.4);
rod([9,7,1],[9,7,2],0.4);
rod([9,7,1],[9,8,1],0.4);
rod([9,8,1],[9,8,2],0.4);
rod([9,8,2],[9,8,3],0.4);
rod([7,8,5],[7,8,6],0.4);
rod([7,7,5],[7,8,5],0.4);
rod([7,6,5],[7,7,5],0.4);
rod([6,6,6],[7,6,6],0.4);
rod([5,6,6],[6,6,6],0.4);
rod([5,6,5],[5,7,5],0.4);
rod([4,3,5],[4,4,5],0.4);
rod([5,3,5],[5,3,6],0.4);
rod([4,4,5],[4,5,5],0.4);
rod([4,5,5],[5,5,5],0.4);
rod([7,5,3],[7,5,4],0.4);
rod([7,6,2],[8,6,2],0.4);
rod([8,6,1],[9,6,1],0.4);
rod([9,6,1],[10,6,1],0.4);
rod([10,5,1],[10,6,1],0.4);
rod([10,4,1],[10,5,1],0.4);
rod([10,6,1],[10,7,1],0.4);
rod([8,5,1],[8,6,1],0.4);
rod([8,5,1],[8,5,2],0.4);
rod([8,4,2],[8,5,2],0.4);
rod([6,4,2],[7,4,2],0.4);
rod([5,4,2],[6,4,2],0.4);
rod([6,3,2],[6,4,2],0.4);
rod([6,3,2],[7,3,2],0.4);
rod([6,1,4],[7,1,4],0.4);
rod([6,1,4],[6,1,5],0.4);
rod([6,2,4],[6,2,5],0.4);
rod([6,2,1],[6,2,2],0.4);
rod([6,2,1],[6,3,1],0.4);
rod([5,3,1],[6,3,1],0.4);
rod([5,3,1],[5,3,2],0.4);
rod([4,2,4],[4,3,4],0.4);
rod([3,3,4],[3,3,5],0.4);
rod([3,2,5],[3,3,5],0.4);
rod([2,3,5],[3,3,5],0.4);
rod([1,2,5],[2,2,5],0.4);
rod([2,3,4],[3,3,4],0.4);
rod([2,3,3],[2,3,4],0.4);
rod([2,4,3],[3,4,3],0.4);
rod([3,3,3],[3,4,3],0.4);
rod([4,5,6],[4,6,6],0.4);
rod([4,6,5],[4,6,6],0.4);
rod([2,8,3],[2,8,4],0.4);
rod([4,9,2],[4,10,2],0.4);
rod([4,10,2],[4,10,3],0.4);
rod([3,6,3],[3,7,3],0.4);
rod([2,6,3],[3,6,3],0.4);
rod([2,6,3],[2,6,4],0.4);
rod([1,6,2],[1,6,3],0.4);
rod([1,6,3],[1,6,4],0.4);
rod([1,6,6],[1,6,7],0.4);
rod([1,5,6],[1,6,6],0.4);
rod([1,5,5],[1,5,6],0.4);
rod([1,5,4],[1,5,5],0.4);
rod([1,5,4],[2,5,4],0.4);
rod([3,8,4],[4,8,4],0.4);
rod([3,10,4],[3,10,5],0.4);
rod([5,9,5],[5,10,5],0.4);
rod([5,6,8],[5,7,8],0.4);
rod([5,8,7],[6,8,7],0.4);
rod([6,7,7],[6,8,7],0.4);
rod([4,6,10],[4,7,10],0.4);
rod([4,5,10],[4,6,10],0.4);
rod([4,5,10],[5,5,10],0.4);
rod([4,4,10],[4,5,10],0.4);
rod([4,4,9],[4,4,10],0.4);
rod([4,3,9],[4,4,9],0.4);
rod([4,3,8],[4,3,9],0.4);
rod([3,3,8],[3,3,9],0.4);
rod([3,2,8],[3,3,8],0.4);
rod([3,1,7],[3,2,7],0.4);
rod([5,2,8],[6,2,8],0.4);
rod([6,2,8],[6,2,9],0.4);
rod([5,3,9],[6,3,9],0.4);
rod([5,3,9],[5,3,10],0.4);
rod([5,2,9],[5,3,9],0.4);
rod([4,2,9],[5,2,9],0.4);
rod([4,2,9],[4,2,10],0.4);
rod([4,1,10],[4,2,10],0.4);
rod([4,1,7],[4,2,7],0.4);
rod([3,1,6],[4,1,6],0.4);
rod([1,4,7],[2,4,7],0.4);
rod([1,4,7],[1,4,8],0.4);
rod([1,2,8],[1,3,8],0.4);
rod([2,1,8],[2,2,8],0.4);
rod([3,2,8],[3,2,9],0.4);
rod([3,2,9],[3,2,10],0.4);
rod([4,2,10],[4,3,10],0.4);
rod([4,3,8],[4,4,8],0.4);
rod([4,4,9],[5,4,9],0.4);
rod([5,4,9],[5,5,9],0.4);
rod([6,4,9],[6,5,9],0.4);
rod([6,6,7],[7,6,7],0.4);
rod([8,6,7],[8,6,8],0.4);
rod([8,5,8],[8,6,8],0.4);
rod([9,3,7],[9,3,8],0.4);
rod([9,2,8],[9,3,8],0.4);
rod([10,2,7],[10,3,7],0.4);
rod([10,3,7],[10,3,8],0.4);
rod([8,2,7],[9,2,7],0.4);
rod([7,1,7],[8,1,7],0.4);
rod([6,2,9],[6,2,10],0.4);
rod([9,1,10],[10,1,10],0.4);
rod([10,1,8],[10,1,9],0.4);
rod([10,1,8],[10,2,8],0.4);
rod([7,4,7],[8,4,7],0.4);
rod([9,4,7],[9,4,8],0.4);
rod([9,4,8],[9,5,8],0.4);
rod([9,4,8],[9,4,9],0.4);
rod([8,4,9],[9,4,9],0.4);
rod([9,3,10],[10,3,10],0.4);
rod([7,2,8],[7,2,9],0.4);
rod([5,1,10],[6,1,10],0.4);
rod([3,1,10],[4,1,10],0.4);
rod([5,1,10],[5,2,10],0.4);
rod([3,4,10],[4,4,10],0.4);
rod([4,4,9],[4,5,9],0.4);
rod([3,4,8],[3,4,9],0.4);
rod([4,1,5],[4,1,6],0.4);
rod([3,1,5],[4,1,5],0.4);
rod([5,3,6],[6,3,6],0.4);
rod([7,1,5],[7,2,5],0.4);
rod([6,3,5],[6,3,6],0.4);
rod([6,3,4],[6,3,5],0.4);
rod([6,1,1],[6,2,1],0.4);
rod([6,1,1],[7,1,1],0.4);
rod([7,1,1],[7,2,1],0.4);
rod([9,1,2],[9,2,2],0.4);
rod([9,1,2],[9,1,3],0.4);
rod([9,1,2],[10,1,2],0.4);
rod([10,1,1],[10,1,2],0.4);
rod([9,1,1],[10,1,1],0.4);
rod([9,3,1],[9,4,1],0.4);
rod([9,5,2],[10,5,2],0.4);
rod([9,5,1],[9,5,2],0.4);
rod([7,5,5],[7,6,5],0.4);
rod([10,1,3],[10,2,3],0.4);
rod([8,3,7],[9,3,7],0.4);
rod([7,3,8],[7,3,9],0.4);
rod([2,1,8],[2,1,9],0.4);
rod([9,2,10],[10,2,10],0.4);
rod([8,3,10],[8,4,10],0.4);
rod([8,4,10],[8,5,10],0.4);
rod([9,5,9],[9,5,10],0.4);
rod([9,5,10],[10,5,10],0.4);
rod([10,5,10],[10,6,10],0.4);
rod([10,4,10],[10,5,10],0.4);
rod([9,4,10],[10,4,10],0.4);
rod([7,1,8],[7,1,9],0.4);
rod([8,1,8],[8,2,8],0.4);
rod([9,5,5],[9,6,5],0.4);
rod([9,6,5],[10,6,5],0.4);
rod([10,7,4],[10,8,4],0.4);
rod([9,7,3],[10,7,3],0.4);
rod([9,8,3],[9,9,3],0.4);
rod([10,8,4],[10,8,5],0.4);
rod([10,8,5],[10,9,5],0.4);
rod([10,9,5],[10,9,6],0.4);
rod([10,9,5],[10,10,5],0.4);
rod([10,10,5],[10,10,6],0.4);
rod([9,10,6],[10,10,6],0.4);
rod([9,10,5],[9,10,6],0.4);
rod([9,10,4],[9,10,5],0.4);
rod([9,10,3],[9,10,4],0.4);
rod([9,9,3],[10,9,3],0.4);
rod([8,9,3],[9,9,3],0.4);
rod([9,9,2],[9,9,3],0.4);
rod([9,9,1],[9,9,2],0.4);
rod([9,9,1],[9,10,1],0.4);
rod([9,10,1],[10,10,1],0.4);
rod([8,9,2],[8,10,2],0.4);
rod([7,9,2],[7,9,3],0.4);
rod([8,10,3],[8,10,4],0.4);
rod([7,10,4],[8,10,4],0.4);
rod([6,10,4],[7,10,4],0.4);
rod([4,10,1],[5,10,1],0.4);
rod([3,10,1],[4,10,1],0.4);
rod([4,8,2],[4,9,2],0.4);
rod([3,8,2],[3,8,3],0.4);
rod([2,8,2],[3,8,2],0.4);
rod([2,8,1],[2,8,2],0.4);
rod([1,8,1],[2,8,1],0.4);
rod([1,8,1],[1,8,2],0.4);
rod([1,7,2],[1,8,2],0.4);
rod([1,7,1],[1,7,2],0.4);
rod([1,7,2],[2,7,2],0.4);
rod([1,7,1],[2,7,1],0.4);
rod([3,6,1],[4,6,1],0.4);
rod([4,6,1],[4,7,1],0.4);
rod([4,7,1],[4,8,1],0.4);
rod([4,8,1],[5,8,1],0.4);
rod([5,6,1],[5,7,1],0.4);
rod([2,4,4],[2,5,4],0.4);
rod([1,4,4],[2,4,4],0.4);
rod([1,4,5],[1,5,5],0.4);
rod([1,3,4],[1,4,4],0.4);
rod([1,3,4],[1,3,5],0.4);
rod([2,3,5],[2,4,5],0.4);
rod([2,4,5],[2,5,5],0.4);
rod([2,10,7],[3,10,7],0.4);
rod([5,6,10],[5,7,10],0.4);
rod([5,6,9],[5,6,10],0.4);
rod([5,6,9],[6,6,9],0.4);
rod([9,7,10],[10,7,10],0.4);
rod([5,6,10],[6,6,10],0.4);
rod([6,6,10],[7,6,10],0.4);
rod([7,5,10],[7,6,10],0.4);
rod([6,3,9],[6,3,10],0.4);
rod([7,3,10],[7,4,10],0.4);
rod([6,4,10],[7,4,10],0.4);
rod([5,5,8],[6,5,8],0.4);
rod([4,6,3],[4,6,4],0.4);
rod([3,5,5],[3,5,6],0.4);
rod([2,4,5],[3,4,5],0.4);
rod([4,1,4],[4,2,4],0.4);
rod([1,2,4],[1,2,5],0.4);
rod([1,3,5],[1,3,6],0.4);
rod([1,2,6],[1,3,6],0.4);
rod([2,2,6],[2,3,6],0.4);
rod([1,1,3],[1,2,3],0.4);
rod([3,2,3],[3,2,4],0.4);
rod([2,2,2],[2,2,3],0.4);
rod([3,5,1],[3,5,2],0.4);
rod([8,5,5],[8,6,5],0.4);
rod([8,7,5],[8,7,6],0.4);
rod([7,7,6],[8,7,6],0.4);
rod([8,7,4],[8,7,5],0.4);
rod([8,8,7],[8,8,8],0.4);
rod([8,7,8],[8,8,8],0.4);
rod([8,7,8],[9,7,8],0.4);
rod([7,7,8],[8,7,8],0.4);
rod([8,10,8],[9,10,8],0.4);
rod([9,10,8],[10,10,8],0.4);
rod([10,10,7],[10,10,8],0.4);
rod([9,10,7],[10,10,7],0.4);
rod([9,9,5],[9,10,5],0.4);
rod([7,6,10],[8,6,10],0.4);
rod([8,8,8],[9,8,8],0.4);
rod([9,8,8],[10,8,8],0.4);
rod([10,7,8],[10,8,8],0.4);
rod([9,6,8],[9,7,8],0.4);
rod([9,6,7],[9,7,7],0.4);
rod([9,6,7],[10,6,7],0.4);
rod([10,6,7],[10,7,7],0.4);
rod([9,6,6],[10,6,6],0.4);
rod([8,4,1],[8,4,2],0.4);
rod([9,1,8],[9,1,9],0.4);
rod([5,2,3],[5,3,3],0.4);
rod([5,3,3],[5,3,4],0.4);
rod([8,4,8],[8,4,9],0.4);
rod([8,3,8],[8,4,8],0.4);
rod([7,2,5],[7,3,5],0.4);
rod([6,3,4],[6,4,4],0.4);
rod([8,6,3],[8,6,4],0.4);
rod([8,6,4],[9,6,4],0.4);
rod([10,6,7],[10,6,8],0.4);
rod([9,8,6],[10,8,6],0.4);
rod([10,9,6],[10,9,7],0.4);
rod([10,8,7],[10,9,7],0.4);
rod([9,8,7],[10,8,7],0.4);
rod([7,6,9],[8,6,9],0.4);
rod([7,6,4],[7,7,4],0.4);
rod([6,4,7],[6,4,8],0.4);
rod([1,2,1],[1,2,2],0.4);
rod([6,4,3],[7,4,3],0.4);
rod([4,2,4],[5,2,4],0.4);
rod([5,1,4],[6,1,4],0.4);
rod([5,2,1],[6,2,1],0.4);
rod([5,1,1],[5,2,1],0.4);
rod([4,1,1],[5,1,1],0.4);
rod([1,2,3],[1,3,3],0.4);
rod([1,5,6],[1,5,7],0.4);
rod([1,6,10],[1,7,10],0.4);
rod([3,3,9],[3,3,10],0.4);
rod([2,7,1],[3,7,1],0.4);
rod([3,7,1],[3,8,1],0.4);
rod([2,8,1],[2,9,1],0.4);
rod([1,9,1],[2,9,1],0.4);
rod([1,9,1],[1,9,2],0.4);
rod([6,9,4],[6,10,4],0.4);
rod([7,8,1],[7,9,1],0.4);
rod([7,7,1],[7,8,1],0.4);
rod([5,7,3],[5,8,3],0.4);
rod([5,4,3],[5,5,3],0.4);
rod([5,5,5],[6,5,5],0.4);
rod([5,3,10],[5,4,10],0.4);
rod([10,9,9],[10,10,9],0.4);
rod([8,10,7],[8,10,8],0.4);
rod([9,9,8],[9,10,8],0.4);
rod([9,9,8],[10,9,8],0.4);
rod([9,9,7],[9,10,7],0.4);
rod([1,9,2],[2,9,2],0.4);
rod([1,10,2],[2,10,2],0.4);
rod([2,10,1],[3,10,1],0.4);
rod([9,6,3],[9,6,4],0.4);
rod([8,9,5],[9,9,5],0.4);
rod([8,9,4],[8,9,5],0.4);
rod([7,9,4],[8,9,4],0.4);
rod([6,7,4],[6,8,4],0.4);
rod([6,6,3],[7,6,3],0.4);
rod([5,5,10],[6,5,10],0.4);
rod([8,9,7],[8,9,8],0.4);
rod([9,6,8],[9,6,9],0.4);
rod([9,6,9],[9,6,10],0.4);
rod([6,9,5],[7,9,5],0.4);
rod([7,9,5],[7,9,6],0.4);
rod([7,8,1],[8,8,1],0.4);
rod([8,8,1],[8,8,2],0.4);
rod([9,8,2],[10,8,2],0.4);
rod([7,2,1],[7,3,1],0.4);
rod([3,1,1],[4,1,1],0.4);
rod([2,1,1],[3,1,1],0.4);
rod([10,8,9],[10,8,10],0.4);
rod([2,3,10],[2,4,10],0.4);
rod([1,5,8],[1,6,8],0.4);
rod([1,4,6],[1,4,7],0.4);
rod([1,6,1],[1,6,2],0.4);
rod([1,1,7],[1,2,7],0.4);
rod([1,1,8],[2,1,8],0.4);
rod([6,10,5],[6,10,6],0.4);
rod([6,10,5],[7,10,5],0.4);
rod([7,10,5],[8,10,5],0.4);
rod([8,8,6],[8,9,6],0.4);
rod([8,9,6],[9,9,6],0.4);
rod([8,10,6],[8,10,7],0.4);
rod([8,7,7],[8,8,7],0.4);
rod([6,1,2],[6,2,2],0.4);
rod([5,1,2],[6,1,2],0.4);
rod([6,5,1],[7,5,1],0.4);
rod([8,6,2],[8,7,2],0.4);
rod([7,4,1],[7,5,1],0.4);
rod([7,7,1],[8,7,1],0.4);
rod([8,9,1],[8,10,1],0.4);
rod([8,7,3],[8,8,3],0.4);
rod([9,8,3],[10,8,3],0.4);
rod([8,10,2],[9,10,2],0.4);
rod([9,10,2],[10,10,2],0.4);
rod([9,9,4],[9,10,4],0.4);
rod([9,9,4],[10,9,4],0.4);
rod([2,9,5],[2,10,5],0.4);
rod([1,10,1],[2,10,1],0.4);
rod([10,6,2],[10,7,2],0.4);
rod([9,10,3],[10,10,3],0.4);
rod([10,9,1],[10,10,1],0.4);
rod([10,9,2],[10,10,2],0.4);
rod([10,7,1],[10,8,1],0.4);
rod([9,10,4],[10,10,4],0.4);
ball([1,1,1],0.4);
ball([1,1,2],0.4);
ball([1,1,3],0.4);
ball([1,1,4],0.4);
ball([1,1,5],0.4);
ball([1,1,6],0.4);
ball([1,1,7],0.4);
ball([1,1,8],0.4);
ball([1,1,9],0.4);
ball([1,1,10],0.4);
ball([1,2,1],0.4);
ball([1,2,2],0.4);
ball([1,2,3],0.4);
ball([1,2,4],0.4);
ball([1,2,5],0.4);
ball([1,2,6],0.4);
ball([1,2,7],0.4);
ball([1,2,8],0.4);
ball([1,2,9],0.4);
ball([1,2,10],0.4);
ball([1,3,1],0.4);
ball([1,3,2],0.4);
ball([1,3,3],0.4);
ball([1,3,4],0.4);
ball([1,3,5],0.4);
ball([1,3,6],0.4);
ball([1,3,7],0.4);
ball([1,3,8],0.4);
ball([1,3,9],0.4);
ball([1,3,10],0.4);
ball([1,4,1],0.4);
ball([1,4,2],0.4);
ball([1,4,3],0.4);
ball([1,4,4],0.4);
ball([1,4,5],0.4);
ball([1,4,6],0.4);
ball([1,4,7],0.4);
ball([1,4,8],0.4);
ball([1,4,9],0.4);
ball([1,4,10],0.4);
ball([1,5,1],0.4);
ball([1,5,2],0.4);
ball([1,5,3],0.4);
ball([1,5,4],0.4);
ball([1,5,5],0.4);
ball([1,5,6],0.4);
ball([1,5,7],0.4);
ball([1,5,8],0.4);
ball([1,5,9],0.4);
ball([1,5,10],0.4);
ball([1,6,1],0.4);
ball([1,6,2],0.4);
ball([1,6,3],0.4);
ball([1,6,4],0.4);
ball([1,6,5],0.4);
ball([1,6,6],0.4);
ball([1,6,7],0.4);
ball([1,6,8],0.4);
ball([1,6,9],0.4);
ball([1,6,10],0.4);
ball([1,7,1],0.4);
ball([1,7,2],0.4);
ball([1,7,3],0.4);
ball([1,7,4],0.4);
ball([1,7,5],0.4);
ball([1,7,6],0.4);
ball([1,7,7],0.4);
ball([1,7,8],0.4);
ball([1,7,9],0.4);
ball([1,7,10],0.4);
ball([1,8,1],0.4);
ball([1,8,2],0.4);
ball([1,8,3],0.4);
ball([1,8,4],0.4);
ball([1,8,5],0.4);
ball([1,8,6],0.4);
ball([1,8,7],0.4);
ball([1,8,8],0.4);
ball([1,8,9],0.4);
ball([1,8,10],0.4);
ball([1,9,1],0.4);
ball([1,9,2],0.4);
ball([1,9,3],0.4);
ball([1,9,4],0.4);
ball([1,9,5],0.4);
ball([1,9,6],0.4);
ball([1,9,7],0.4);
ball([1,9,8],0.4);
ball([1,9,9],0.4);
ball([1,9,10],0.4);
ball([1,10,1],0.4);
ball([1,10,2],0.4);
ball([1,10,3],0.4);
ball([1,10,4],0.4);
ball([1,10,5],0.4);
ball([1,10,6],0.4);
ball([1,10,7],0.4);
ball([1,10,8],0.4);
ball([1,10,9],0.4);
ball([1,10,10],0.4);
ball([2,1,1],0.4);
ball([2,1,2],0.4);
ball([2,1,3],0.4);
ball([2,1,4],0.4);
ball([2,1,5],0.4);
ball([2,1,6],0.4);
ball([2,1,7],0.4);
ball([2,1,8],0.4);
ball([2,1,9],0.4);
ball([2,1,10],0.4);
ball([2,2,1],0.4);
ball([2,2,2],0.4);
ball([2,2,3],0.4);
ball([2,2,4],0.4);
ball([2,2,5],0.4);
ball([2,2,6],0.4);
ball([2,2,7],0.4);
ball([2,2,8],0.4);
ball([2,2,9],0.4);
ball([2,2,10],0.4);
ball([2,3,1],0.4);
ball([2,3,2],0.4);
ball([2,3,3],0.4);
ball([2,3,4],0.4);
ball([2,3,5],0.4);
ball([2,3,6],0.4);
ball([2,3,7],0.4);
ball([2,3,8],0.4);
ball([2,3,9],0.4);
ball([2,3,10],0.4);
ball([2,4,1],0.4);
ball([2,4,2],0.4);
ball([2,4,3],0.4);
ball([2,4,4],0.4);
ball([2,4,5],0.4);
ball([2,4,6],0.4);
ball([2,4,7],0.4);
ball([2,4,8],0.4);
ball([2,4,9],0.4);
ball([2,4,10],0.4);
ball([2,5,1],0.4);
ball([2,5,2],0.4);
ball([2,5,3],0.4);
ball([2,5,4],0.4);
ball([2,5,5],0.4);
ball([2,5,6],0.4);
ball([2,5,7],0.4);
ball([2,5,8],0.4);
ball([2,5,9],0.4);
ball([2,5,10],0.4);
ball([2,6,1],0.4);
ball([2,6,2],0.4);
ball([2,6,3],0.4);
ball([2,6,4],0.4);
ball([2,6,5],0.4);
ball([2,6,6],0.4);
ball([2,6,7],0.4);
ball([2,6,8],0.4);
ball([2,6,9],0.4);
ball([2,6,10],0.4);
ball([2,7,1],0.4);
ball([2,7,2],0.4);
ball([2,7,3],0.4);
ball([2,7,4],0.4);
ball([2,7,5],0.4);
ball([2,7,6],0.4);
ball([2,7,7],0.4);
ball([2,7,8],0.4);
ball([2,7,9],0.4);
ball([2,7,10],0.4);
ball([2,8,1],0.4);
ball([2,8,2],0.4);
ball([2,8,3],0.4);
ball([2,8,4],0.4);
ball([2,8,5],0.4);
ball([2,8,6],0.4);
ball([2,8,7],0.4);
ball([2,8,8],0.4);
ball([2,8,9],0.4);
ball([2,8,10],0.4);
ball([2,9,1],0.4);
ball([2,9,2],0.4);
ball([2,9,3],0.4);
ball([2,9,4],0.4);
ball([2,9,5],0.4);
ball([2,9,6],0.4);
ball([2,9,7],0.4);
ball([2,9,8],0.4);
ball([2,9,9],0.4);
ball([2,9,10],0.4);
ball([2,10,1],0.4);
ball([2,10,2],0.4);
ball([2,10,3],0.4);
ball([2,10,4],0.4);
ball([2,10,5],0.4);
ball([2,10,6],0.4);
ball([2,10,7],0.4);
ball([2,10,8],0.4);
ball([2,10,9],0.4);
ball([2,10,10],0.4);
ball([3,1,1],0.4);
ball([3,1,2],0.4);
ball([3,1,3],0.4);
ball([3,1,4],0.4);
ball([3,1,5],0.4);
ball([3,1,6],0.4);
ball([3,1,7],0.4);
ball([3,1,8],0.4);
ball([3,1,9],0.4);
ball([3,1,10],0.4);
ball([3,2,1],0.4);
ball([3,2,2],0.4);
ball([3,2,3],0.4);
ball([3,2,4],0.4);
ball([3,2,5],0.4);
ball([3,2,6],0.4);
ball([3,2,7],0.4);
ball([3,2,8],0.4);
ball([3,2,9],0.4);
ball([3,2,10],0.4);
ball([3,3,1],0.4);
ball([3,3,2],0.4);
ball([3,3,3],0.4);
ball([3,3,4],0.4);
ball([3,3,5],0.4);
ball([3,3,6],0.4);
ball([3,3,7],0.4);
ball([3,3,8],0.4);
ball([3,3,9],0.4);
ball([3,3,10],0.4);
ball([3,4,1],0.4);
ball([3,4,2],0.4);
ball([3,4,3],0.4);
ball([3,4,4],0.4);
ball([3,4,5],0.4);
ball([3,4,6],0.4);
ball([3,4,7],0.4);
ball([3,4,8],0.4);
ball([3,4,9],0.4);
ball([3,4,10],0.4);
ball([3,5,1],0.4);
ball([3,5,2],0.4);
ball([3,5,3],0.4);
ball([3,5,4],0.4);
ball([3,5,5],0.4);
ball([3,5,6],0.4);
ball([3,5,7],0.4);
ball([3,5,8],0.4);
ball([3,5,9],0.4);
ball([3,5,10],0.4);
ball([3,6,1],0.4);
ball([3,6,2],0.4);
ball([3,6,3],0.4);
ball([3,6,4],0.4);
ball([3,6,5],0.4);
ball([3,6,6],0.4);
ball([3,6,7],0.4);
ball([3,6,8],0.4);
ball([3,6,9],0.4);
ball([3,6,10],0.4);
ball([3,7,1],0.4);
ball([3,7,2],0.4);
ball([3,7,3],0.4);
ball([3,7,4],0.4);
ball([3,7,5],0.4);
ball([3,7,6],0.4);
ball([3,7,7],0.4);
ball([3,7,8],0.4);
ball([3,7,9],0.4);
ball([3,7,10],0.4);
ball([3,8,1],0.4);
ball([3,8,2],0.4);
ball([3,8,3],0.4);
ball([3,8,4],0.4);
ball([3,8,5],0.4);
ball([3,8,6],0.4);
ball([3,8,7],0.4);
ball([3,8,8],0.4);
ball([3,8,9],0.4);
ball([3,8,10],0.4);
ball([3,9,1],0.4);
ball([3,9,2],0.4);
ball([3,9,3],0.4);
ball([3,9,4],0.4);
ball([3,9,5],0.4);
ball([3,9,6],0.4);
ball([3,9,7],0.4);
ball([3,9,8],0.4);
ball([3,9,9],0.4);
ball([3,9,10],0.4);
ball([3,10,1],0.4);
ball([3,10,2],0.4);
ball([3,10,3],0.4);
ball([3,10,4],0.4);
ball([3,10,5],0.4);
ball([3,10,6],0.4);
ball([3,10,7],0.4);
ball([3,10,8],0.4);
ball([3,10,9],0.4);
ball([3,10,10],0.4);
ball([4,1,1],0.4);
ball([4,1,2],0.4);
ball([4,1,3],0.4);
ball([4,1,4],0.4);
ball([4,1,5],0.4);
ball([4,1,6],0.4);
ball([4,1,7],0.4);
ball([4,1,8],0.4);
ball([4,1,9],0.4);
ball([4,1,10],0.4);
ball([4,2,1],0.4);
ball([4,2,2],0.4);
ball([4,2,3],0.4);
ball([4,2,4],0.4);
ball([4,2,5],0.4);
ball([4,2,6],0.4);
ball([4,2,7],0.4);
ball([4,2,8],0.4);
ball([4,2,9],0.4);
ball([4,2,10],0.4);
ball([4,3,1],0.4);
ball([4,3,2],0.4);
ball([4,3,3],0.4);
ball([4,3,4],0.4);
ball([4,3,5],0.4);
ball([4,3,6],0.4);
ball([4,3,7],0.4);
ball([4,3,8],0.4);
ball([4,3,9],0.4);
ball([4,3,10],0.4);
ball([4,4,1],0.4);
ball([4,4,2],0.4);
ball([4,4,3],0.4);
ball([4,4,4],0.4);
ball([4,4,5],0.4);
ball([4,4,6],0.4);
ball([4,4,7],0.4);
ball([4,4,8],0.4);
ball([4,4,9],0.4);
ball([4,4,10],0.4);
ball([4,5,1],0.4);
ball([4,5,2],0.4);
ball([4,5,3],0.4);
ball([4,5,4],0.4);
ball([4,5,5],0.4);
ball([4,5,6],0.4);
ball([4,5,7],0.4);
ball([4,5,8],0.4);
ball([4,5,9],0.4);
ball([4,5,10],0.4);
ball([4,6,1],0.4);
ball([4,6,2],0.4);
ball([4,6,3],0.4);
ball([4,6,4],0.4);
ball([4,6,5],0.4);
ball([4,6,6],0.4);
ball([4,6,7],0.4);
ball([4,6,8],0.4);
ball([4,6,9],0.4);
ball([4,6,10],0.4);
ball([4,7,1],0.4);
ball([4,7,2],0.4);
ball([4,7,3],0.4);
ball([4,7,4],0.4);
ball([4,7,5],0.4);
ball([4,7,6],0.4);
ball([4,7,7],0.4);
ball([4,7,8],0.4);
ball([4,7,9],0.4);
ball([4,7,10],0.4);
ball([4,8,1],0.4);
ball([4,8,2],0.4);
ball([4,8,3],0.4);
ball([4,8,4],0.4);
ball([4,8,5],0.4);
ball([4,8,6],0.4);
ball([4,8,7],0.4);
ball([4,8,8],0.4);
ball([4,8,9],0.4);
ball([4,8,10],0.4);
ball([4,9,1],0.4);
ball([4,9,2],0.4);
ball([4,9,3],0.4);
ball([4,9,4],0.4);
ball([4,9,5],0.4);
ball([4,9,6],0.4);
ball([4,9,7],0.4);
ball([4,9,8],0.4);
ball([4,9,9],0.4);
ball([4,9,10],0.4);
ball([4,10,1],0.4);
ball([4,10,2],0.4);
ball([4,10,3],0.4);
ball([4,10,4],0.4);
ball([4,10,5],0.4);
ball([4,10,6],0.4);
ball([4,10,7],0.4);
ball([4,10,8],0.4);
ball([4,10,9],0.4);
ball([4,10,10],0.4);
ball([5,1,1],0.4);
ball([5,1,2],0.4);
ball([5,1,3],0.4);
ball([5,1,4],0.4);
ball([5,1,5],0.4);
ball([5,1,6],0.4);
ball([5,1,7],0.4);
ball([5,1,8],0.4);
ball([5,1,9],0.4);
ball([5,1,10],0.4);
ball([5,2,1],0.4);
ball([5,2,2],0.4);
ball([5,2,3],0.4);
ball([5,2,4],0.4);
ball([5,2,5],0.4);
ball([5,2,6],0.4);
ball([5,2,7],0.4);
ball([5,2,8],0.4);
ball([5,2,9],0.4);
ball([5,2,10],0.4);
ball([5,3,1],0.4);
ball([5,3,2],0.4);
ball([5,3,3],0.4);
ball([5,3,4],0.4);
ball([5,3,5],0.4);
ball([5,3,6],0.4);
ball([5,3,7],0.4);
ball([5,3,8],0.4);
ball([5,3,9],0.4);
ball([5,3,10],0.4);
ball([5,4,1],0.4);
ball([5,4,2],0.4);
ball([5,4,3],0.4);
ball([5,4,4],0.4);
ball([5,4,5],0.4);
ball([5,4,6],0.4);
ball([5,4,7],0.4);
ball([5,4,8],0.4);
ball([5,4,9],0.4);
ball([5,4,10],0.4);
ball([5,5,1],0.4);
ball([5,5,2],0.4);
ball([5,5,3],0.4);
ball([5,5,4],0.4);
ball([5,5,5],0.4);
ball([5,5,6],0.4);
ball([5,5,7],0.4);
ball([5,5,8],0.4);
ball([5,5,9],0.4);
ball([5,5,10],0.4);
ball([5,6,1],0.4);
ball([5,6,2],0.4);
ball([5,6,3],0.4);
ball([5,6,4],0.4);
ball([5,6,5],0.4);
ball([5,6,6],0.4);
ball([5,6,7],0.4);
ball([5,6,8],0.4);
ball([5,6,9],0.4);
ball([5,6,10],0.4);
ball([5,7,1],0.4);
ball([5,7,2],0.4);
ball([5,7,3],0.4);
ball([5,7,4],0.4);
ball([5,7,5],0.4);
ball([5,7,6],0.4);
ball([5,7,7],0.4);
ball([5,7,8],0.4);
ball([5,7,9],0.4);
ball([5,7,10],0.4);
ball([5,8,1],0.4);
ball([5,8,2],0.4);
ball([5,8,3],0.4);
ball([5,8,4],0.4);
ball([5,8,5],0.4);
ball([5,8,6],0.4);
ball([5,8,7],0.4);
ball([5,8,8],0.4);
ball([5,8,9],0.4);
ball([5,8,10],0.4);
ball([5,9,1],0.4);
ball([5,9,2],0.4);
ball([5,9,3],0.4);
ball([5,9,4],0.4);
ball([5,9,5],0.4);
ball([5,9,6],0.4);
ball([5,9,7],0.4);
ball([5,9,8],0.4);
ball([5,9,9],0.4);
ball([5,9,10],0.4);
ball([5,10,1],0.4);
ball([5,10,2],0.4);
ball([5,10,3],0.4);
ball([5,10,4],0.4);
ball([5,10,5],0.4);
ball([5,10,6],0.4);
ball([5,10,7],0.4);
ball([5,10,8],0.4);
ball([5,10,9],0.4);
ball([5,10,10],0.4);
ball([6,1,1],0.4);
ball([6,1,2],0.4);
ball([6,1,3],0.4);
ball([6,1,4],0.4);
ball([6,1,5],0.4);
ball([6,1,6],0.4);
ball([6,1,7],0.4);
ball([6,1,8],0.4);
ball([6,1,9],0.4);
ball([6,1,10],0.4);
ball([6,2,1],0.4);
ball([6,2,2],0.4);
ball([6,2,3],0.4);
ball([6,2,4],0.4);
ball([6,2,5],0.4);
ball([6,2,6],0.4);
ball([6,2,7],0.4);
ball([6,2,8],0.4);
ball([6,2,9],0.4);
ball([6,2,10],0.4);
ball([6,3,1],0.4);
ball([6,3,2],0.4);
ball([6,3,3],0.4);
ball([6,3,4],0.4);
ball([6,3,5],0.4);
ball([6,3,6],0.4);
ball([6,3,7],0.4);
ball([6,3,8],0.4);
ball([6,3,9],0.4);
ball([6,3,10],0.4);
ball([6,4,1],0.4);
ball([6,4,2],0.4);
ball([6,4,3],0.4);
ball([6,4,4],0.4);
ball([6,4,5],0.4);
ball([6,4,6],0.4);
ball([6,4,7],0.4);
ball([6,4,8],0.4);
ball([6,4,9],0.4);
ball([6,4,10],0.4);
ball([6,5,1],0.4);
ball([6,5,2],0.4);
ball([6,5,3],0.4);
ball([6,5,4],0.4);
ball([6,5,5],0.4);
ball([6,5,6],0.4);
ball([6,5,7],0.4);
ball([6,5,8],0.4);
ball([6,5,9],0.4);
ball([6,5,10],0.4);
ball([6,6,1],0.4);
ball([6,6,2],0.4);
ball([6,6,3],0.4);
ball([6,6,4],0.4);
ball([6,6,5],0.4);
ball([6,6,6],0.4);
ball([6,6,7],0.4);
ball([6,6,8],0.4);
ball([6,6,9],0.4);
ball([6,6,10],0.4);
ball([6,7,1],0.4);
ball([6,7,2],0.4);
ball([6,7,3],0.4);
ball([6,7,4],0.4);
ball([6,7,5],0.4);
ball([6,7,6],0.4);
ball([6,7,7],0.4);
ball([6,7,8],0.4);
ball([6,7,9],0.4);
ball([6,7,10],0.4);
ball([6,8,1],0.4);
ball([6,8,2],0.4);
ball([6,8,3],0.4);
ball([6,8,4],0.4);
ball([6,8,5],0.4);
ball([6,8,6],0.4);
ball([6,8,7],0.4);
ball([6,8,8],0.4);
ball([6,8,9],0.4);
ball([6,8,10],0.4);
ball([6,9,1],0.4);
ball([6,9,2],0.4);
ball([6,9,3],0.4);
ball([6,9,4],0.4);
ball([6,9,5],0.4);
ball([6,9,6],0.4);
ball([6,9,7],0.4);
ball([6,9,8],0.4);
ball([6,9,9],0.4);
ball([6,9,10],0.4);
ball([6,10,1],0.4);
ball([6,10,2],0.4);
ball([6,10,3],0.4);
ball([6,10,4],0.4);
ball([6,10,5],0.4);
ball([6,10,6],0.4);
ball([6,10,7],0.4);
ball([6,10,8],0.4);
ball([6,10,9],0.4);
ball([6,10,10],0.4);
ball([7,1,1],0.4);
ball([7,1,2],0.4);
ball([7,1,3],0.4);
ball([7,1,4],0.4);
ball([7,1,5],0.4);
ball([7,1,6],0.4);
ball([7,1,7],0.4);
ball([7,1,8],0.4);
ball([7,1,9],0.4);
ball([7,1,10],0.4);
ball([7,2,1],0.4);
ball([7,2,2],0.4);
ball([7,2,3],0.4);
ball([7,2,4],0.4);
ball([7,2,5],0.4);
ball([7,2,6],0.4);
ball([7,2,7],0.4);
ball([7,2,8],0.4);
ball([7,2,9],0.4);
ball([7,2,10],0.4);
ball([7,3,1],0.4);
ball([7,3,2],0.4);
ball([7,3,3],0.4);
ball([7,3,4],0.4);
ball([7,3,5],0.4);
ball([7,3,6],0.4);
ball([7,3,7],0.4);
ball([7,3,8],0.4);
ball([7,3,9],0.4);
ball([7,3,10],0.4);
ball([7,4,1],0.4);
ball([7,4,2],0.4);
ball([7,4,3],0.4);
ball([7,4,4],0.4);
ball([7,4,5],0.4);
ball([7,4,6],0.4);
ball([7,4,7],0.4);
ball([7,4,8],0.4);
ball([7,4,9],0.4);
ball([7,4,10],0.4);
ball([7,5,1],0.4);
ball([7,5,2],0.4);
ball([7,5,3],0.4);
ball([7,5,4],0.4);
ball([7,5,5],0.4);
ball([7,5,6],0.4);
ball([7,5,7],0.4);
ball([7,5,8],0.4);
ball([7,5,9],0.4);
ball([7,5,10],0.4);
ball([7,6,1],0.4);
ball([7,6,2],0.4);
ball([7,6,3],0.4);
ball([7,6,4],0.4);
ball([7,6,5],0.4);
ball([7,6,6],0.4);
ball([7,6,7],0.4);
ball([7,6,8],0.4);
ball([7,6,9],0.4);
ball([7,6,10],0.4);
ball([7,7,1],0.4);
ball([7,7,2],0.4);
ball([7,7,3],0.4);
ball([7,7,4],0.4);
ball([7,7,5],0.4);
ball([7,7,6],0.4);
ball([7,7,7],0.4);
ball([7,7,8],0.4);
ball([7,7,9],0.4);
ball([7,7,10],0.4);
ball([7,8,1],0.4);
ball([7,8,2],0.4);
ball([7,8,3],0.4);
ball([7,8,4],0.4);
ball([7,8,5],0.4);
ball([7,8,6],0.4);
ball([7,8,7],0.4);
ball([7,8,8],0.4);
ball([7,8,9],0.4);
ball([7,8,10],0.4);
ball([7,9,1],0.4);
ball([7,9,2],0.4);
ball([7,9,3],0.4);
ball([7,9,4],0.4);
ball([7,9,5],0.4);
ball([7,9,6],0.4);
ball([7,9,7],0.4);
ball([7,9,8],0.4);
ball([7,9,9],0.4);
ball([7,9,10],0.4);
ball([7,10,1],0.4);
ball([7,10,2],0.4);
ball([7,10,3],0.4);
ball([7,10,4],0.4);
ball([7,10,5],0.4);
ball([7,10,6],0.4);
ball([7,10,7],0.4);
ball([7,10,8],0.4);
ball([7,10,9],0.4);
ball([7,10,10],0.4);
ball([8,1,1],0.4);
ball([8,1,2],0.4);
ball([8,1,3],0.4);
ball([8,1,4],0.4);
ball([8,1,5],0.4);
ball([8,1,6],0.4);
ball([8,1,7],0.4);
ball([8,1,8],0.4);
ball([8,1,9],0.4);
ball([8,1,10],0.4);
ball([8,2,1],0.4);
ball([8,2,2],0.4);
ball([8,2,3],0.4);
ball([8,2,4],0.4);
ball([8,2,5],0.4);
ball([8,2,6],0.4);
ball([8,2,7],0.4);
ball([8,2,8],0.4);
ball([8,2,9],0.4);
ball([8,2,10],0.4);
ball([8,3,1],0.4);
ball([8,3,2],0.4);
ball([8,3,3],0.4);
ball([8,3,4],0.4);
ball([8,3,5],0.4);
ball([8,3,6],0.4);
ball([8,3,7],0.4);
ball([8,3,8],0.4);
ball([8,3,9],0.4);
ball([8,3,10],0.4);
ball([8,4,1],0.4);
ball([8,4,2],0.4);
ball([8,4,3],0.4);
ball([8,4,4],0.4);
ball([8,4,5],0.4);
ball([8,4,6],0.4);
ball([8,4,7],0.4);
ball([8,4,8],0.4);
ball([8,4,9],0.4);
ball([8,4,10],0.4);
ball([8,5,1],0.4);
ball([8,5,2],0.4);
ball([8,5,3],0.4);
ball([8,5,4],0.4);
ball([8,5,5],0.4);
ball([8,5,6],0.4);
ball([8,5,7],0.4);
ball([8,5,8],0.4);
ball([8,5,9],0.4);
ball([8,5,10],0.4);
ball([8,6,1],0.4);
ball([8,6,2],0.4);
ball([8,6,3],0.4);
ball([8,6,4],0.4);
ball([8,6,5],0.4);
ball([8,6,6],0.4);
ball([8,6,7],0.4);
ball([8,6,8],0.4);
ball([8,6,9],0.4);
ball([8,6,10],0.4);
ball([8,7,1],0.4);
ball([8,7,2],0.4);
ball([8,7,3],0.4);
ball([8,7,4],0.4);
ball([8,7,5],0.4);
ball([8,7,6],0.4);
ball([8,7,7],0.4);
ball([8,7,8],0.4);
ball([8,7,9],0.4);
ball([8,7,10],0.4);
ball([8,8,1],0.4);
ball([8,8,2],0.4);
ball([8,8,3],0.4);
ball([8,8,4],0.4);
ball([8,8,5],0.4);
ball([8,8,6],0.4);
ball([8,8,7],0.4);
ball([8,8,8],0.4);
ball([8,8,9],0.4);
ball([8,8,10],0.4);
ball([8,9,1],0.4);
ball([8,9,2],0.4);
ball([8,9,3],0.4);
ball([8,9,4],0.4);
ball([8,9,5],0.4);
ball([8,9,6],0.4);
ball([8,9,7],0.4);
ball([8,9,8],0.4);
ball([8,9,9],0.4);
ball([8,9,10],0.4);
ball([8,10,1],0.4);
ball([8,10,2],0.4);
ball([8,10,3],0.4);
ball([8,10,4],0.4);
ball([8,10,5],0.4);
ball([8,10,6],0.4);
ball([8,10,7],0.4);
ball([8,10,8],0.4);
ball([8,10,9],0.4);
ball([8,10,10],0.4);
ball([9,1,1],0.4);
ball([9,1,2],0.4);
ball([9,1,3],0.4);
ball([9,1,4],0.4);
ball([9,1,5],0.4);
ball([9,1,6],0.4);
ball([9,1,7],0.4);
ball([9,1,8],0.4);
ball([9,1,9],0.4);
ball([9,1,10],0.4);
ball([9,2,1],0.4);
ball([9,2,2],0.4);
ball([9,2,3],0.4);
ball([9,2,4],0.4);
ball([9,2,5],0.4);
ball([9,2,6],0.4);
ball([9,2,7],0.4);
ball([9,2,8],0.4);
ball([9,2,9],0.4);
ball([9,2,10],0.4);
ball([9,3,1],0.4);
ball([9,3,2],0.4);
ball([9,3,3],0.4);
ball([9,3,4],0.4);
ball([9,3,5],0.4);
ball([9,3,6],0.4);
ball([9,3,7],0.4);
ball([9,3,8],0.4);
ball([9,3,9],0.4);
ball([9,3,10],0.4);
ball([9,4,1],0.4);
ball([9,4,2],0.4);
ball([9,4,3],0.4);
ball([9,4,4],0.4);
ball([9,4,5],0.4);
ball([9,4,6],0.4);
ball([9,4,7],0.4);
ball([9,4,8],0.4);
ball([9,4,9],0.4);
ball([9,4,10],0.4);
ball([9,5,1],0.4);
ball([9,5,2],0.4);
ball([9,5,3],0.4);
ball([9,5,4],0.4);
ball([9,5,5],0.4);
ball([9,5,6],0.4);
ball([9,5,7],0.4);
ball([9,5,8],0.4);
ball([9,5,9],0.4);
ball([9,5,10],0.4);
ball([9,6,1],0.4);
ball([9,6,2],0.4);
ball([9,6,3],0.4);
ball([9,6,4],0.4);
ball([9,6,5],0.4);
ball([9,6,6],0.4);
ball([9,6,7],0.4);
ball([9,6,8],0.4);
ball([9,6,9],0.4);
ball([9,6,10],0.4);
ball([9,7,1],0.4);
ball([9,7,2],0.4);
ball([9,7,3],0.4);
ball([9,7,4],0.4);
ball([9,7,5],0.4);
ball([9,7,6],0.4);
ball([9,7,7],0.4);
ball([9,7,8],0.4);
ball([9,7,9],0.4);
ball([9,7,10],0.4);
ball([9,8,1],0.4);
ball([9,8,2],0.4);
ball([9,8,3],0.4);
ball([9,8,4],0.4);
ball([9,8,5],0.4);
ball([9,8,6],0.4);
ball([9,8,7],0.4);
ball([9,8,8],0.4);
ball([9,8,9],0.4);
ball([9,8,10],0.4);
ball([9,9,1],0.4);
ball([9,9,2],0.4);
ball([9,9,3],0.4);
ball([9,9,4],0.4);
ball([9,9,5],0.4);
ball([9,9,6],0.4);
ball([9,9,7],0.4);
ball([9,9,8],0.4);
ball([9,9,9],0.4);
ball([9,9,10],0.4);
ball([9,10,1],0.4);
ball([9,10,2],0.4);
ball([9,10,3],0.4);
ball([9,10,4],0.4);
ball([9,10,5],0.4);
ball([9,10,6],0.4);
ball([9,10,7],0.4);
ball([9,10,8],0.4);
ball([9,10,9],0.4);
ball([9,10,10],0.4);
ball([10,1,1],0.4);
ball([10,1,2],0.4);
ball([10,1,3],0.4);
ball([10,1,4],0.4);
ball([10,1,5],0.4);
ball([10,1,6],0.4);
ball([10,1,7],0.4);
ball([10,1,8],0.4);
ball([10,1,9],0.4);
ball([10,1,10],0.4);
ball([10,2,1],0.4);
ball([10,2,2],0.4);
ball([10,2,3],0.4);
ball([10,2,4],0.4);
ball([10,2,5],0.4);
ball([10,2,6],0.4);
ball([10,2,7],0.4);
ball([10,2,8],0.4);
ball([10,2,9],0.4);
ball([10,2,10],0.4);
ball([10,3,1],0.4);
ball([10,3,2],0.4);
ball([10,3,3],0.4);
ball([10,3,4],0.4);
ball([10,3,5],0.4);
ball([10,3,6],0.4);
ball([10,3,7],0.4);
ball([10,3,8],0.4);
ball([10,3,9],0.4);
ball([10,3,10],0.4);
ball([10,4,1],0.4);
ball([10,4,2],0.4);
ball([10,4,3],0.4);
ball([10,4,4],0.4);
ball([10,4,5],0.4);
ball([10,4,6],0.4);
ball([10,4,7],0.4);
ball([10,4,8],0.4);
ball([10,4,9],0.4);
ball([10,4,10],0.4);
ball([10,5,1],0.4);
ball([10,5,2],0.4);
ball([10,5,3],0.4);
ball([10,5,4],0.4);
ball([10,5,5],0.4);
ball([10,5,6],0.4);
ball([10,5,7],0.4);
ball([10,5,8],0.4);
ball([10,5,9],0.4);
ball([10,5,10],0.4);
ball([10,6,1],0.4);
ball([10,6,2],0.4);
ball([10,6,3],0.4);
ball([10,6,4],0.4);
ball([10,6,5],0.4);
ball([10,6,6],0.4);
ball([10,6,7],0.4);
ball([10,6,8],0.4);
ball([10,6,9],0.4);
ball([10,6,10],0.4);
ball([10,7,1],0.4);
ball([10,7,2],0.4);
ball([10,7,3],0.4);
ball([10,7,4],0.4);
ball([10,7,5],0.4);
ball([10,7,6],0.4);
ball([10,7,7],0.4);
ball([10,7,8],0.4);
ball([10,7,9],0.4);
ball([10,7,10],0.4);
ball([10,8,1],0.4);
ball([10,8,2],0.4);
ball([10,8,3],0.4);
ball([10,8,4],0.4);
ball([10,8,5],0.4);
ball([10,8,6],0.4);
ball([10,8,7],0.4);
ball([10,8,8],0.4);
ball([10,8,9],0.4);
ball([10,8,10],0.4);
ball([10,9,1],0.4);
ball([10,9,2],0.4);
ball([10,9,3],0.4);
ball([10,9,4],0.4);
ball([10,9,5],0.4);
ball([10,9,6],0.4);
ball([10,9,7],0.4);
ball([10,9,8],0.4);
ball([10,9,9],0.4);
ball([10,9,10],0.4);
ball([10,10,1],0.4);
ball([10,10,2],0.4);
ball([10,10,3],0.4);
ball([10,10,4],0.4);
ball([10,10,5],0.4);
ball([10,10,6],0.4);
ball([10,10,7],0.4);
ball([10,10,8],0.4);
ball([10,10,9],0.4);
ball([10,10,10],0.4);
}
// Menger Sponge by Hans Loeblich
// From https://gist.github.com/thehans/f2bcf3b7d8d5a49378f71e437fa870d0
// The 3d shape is created by the intersection of 3 orthogonal linear_extruded sierpinski carpets.
//menger(100,3);
//menger_cut(100,3);
//animated_menger(100,3);
optimized_menger(4);
// Optimized for smaller ASCII STL file sizes. Object size is scaled so that points fall on whole number coordinates only.
// These file size savings are negligible if you convert to binary STL format anyways (not supported in OpenSCAD, but can be converted after saving)
// This technique is also not applicable to diagonally cut menger sponge
module optimized_menger(n) {
s=pow(3,n);
translate([s/2,s/2,s/2]) menger(s,n);
}
// cube cut along diagonal for ease of printing, two prints will form the whole shape
module menger_cut(size, n) {
difference() {
rotate([45,atan(1/sqrt(2)),0]) menger(size,n);
translate([0,0,-size]) cube(size*2, center=true);
}
}
module menger(s, n) {
intersection() {
rotate([ 0,90,0]) translate([0,0,-s/2-1]) linear_extrude(s+2, convexity=pow(2,n)) sierpinski(s,n);
rotate([90, 0,0]) translate([0,0,-s/2-1]) linear_extrude(s+2, convexity=pow(2,n)) sierpinski(s,n);
rotate([ 0, 0,0]) translate([0,0,-s/2-1]) linear_extrude(s+2, convexity=pow(2,n)) sierpinski(s,n);
}
}
module sierpinski(s, n) {
difference() {
square(s, center=true);
_sierpinski(0,0,s,n);
}
}
module _sierpinski(x, y, s, n) {
translate([x,y]) {
if (n>0) {
i = n-1;
scale([1/3,1/3]) {
square(s, center=true);
if (i>0) {
_sierpinski(-s,-s, s, i);
_sierpinski(-s, 0, s, i);
_sierpinski(-s, s, s, i);
_sierpinski( 0,-s, s, i);
//_sierpinski( 0, 0, s, i);
_sierpinski( 0, s, s, i);
_sierpinski( s,-s, s, i);
_sierpinski( s, 0, s, i);
_sierpinski( s, s, s, i);
}
}
}
}
}
module animated_menger(s, n) {
t0 = get_step_t(0, 6);
t1 = get_step_t(1, 6);
t2 = get_step_t(2, 6);
t3 = get_step_t(3, 6);
t4 = get_step_t(4, 6);
t5 = get_step_t(5, 6);
//echo(t0,t1,t2,t3,t4,t5);
if (t0 > 0) color([1,0,0,0.8]) scale([1.01,1,0.99]) rotate([ 0,90, 0]) translate([0,0,-3*s/2]) linear_extrude(s*t0, convexity=pow(2,n)) sierpinski(s,n);
if (t2 > 0) color([0,1,0,0.8]) scale([0.99,1.01,1]) rotate([90, 0, 0]) translate([0,0,-3*s/2]) linear_extrude(s*t2, convexity=pow(2,n)) sierpinski(s,n);
if (t4 > 0) color([0,0,1,0.8]) scale([1,0.99,1.01]) rotate([ 0, 0, 0]) translate([0,0,-3*s/2]) linear_extrude(s*t4, convexity=pow(2,n)) sierpinski(s,n);
intersection() {
if (t1 > 0) color([1,0,0,0.8]) scale([1.01,1,0.99]) rotate([ 0,90, 0]) translate([0,0,-s/2]) linear_extrude(s*t1, convexity=pow(2,n)) sierpinski(s,n);
if (t3 > 0) color([0,1,0,0.8]) scale([0.99,1.01,1]) rotate([90, 0, 0]) translate([0,0,-s/2]) linear_extrude(s*t3, convexity=pow(2,n)) sierpinski(s,n);
if (t5 > 0) color([0,0,1,0.8]) scale([1,0.99,1.01]) rotate([ 0, 0, 0]) translate([0,0,-s/2]) linear_extrude(s*t5, convexity=pow(2,n)) sierpinski(s,n);
}
}
function get_step_t(step, total) = let(t = $t*total - step) min(1,t);
{
"fileFormatVersion": "1",
"parameterSets": {
"ultrafine": {
"dishFn": "100",
"smoothFn": "100"
},
"coarse": {
"dishFn": "10",
"smoothFn": "10"
}
}
}
include <BOSL2/std.scad>
dishFn=30;
smoothFn=30;
echo("dishFn", dishFn);
echo("smoothFn", smoothFn);
minkowski() {
diff("dish", keep="antenna")
cube(100, center=true)
attach([FRONT,TOP], overlap=33) {
tag("dish") cylinder(h=33.1, d1=0, d2=95, $fn=dishFn);
tag("antenna") cylinder(h=33.1, d=10, $fn=dishFn);
}
sphere(r=5, $fn=smoothFn);
}
include <BOSL2/std.scad>
//$fn=$preview ? 15 : 30;
*offset3d(1)
bottom_half()
difference() {
cube(10, center=true);
xscale(0.9) yscale(1.1)
sphere(d=10);
}
*offset3d(1)
bottom_half()
scale([1.2, 0.8, 1])
cylinder(10, d=2, center=true);
*round3d(2, $fn=5)
minkowski_difference() {
union() {
cube([120,70,70], center=true);
cube([70,120,70], center=true);
cube([70,70,120], center=true);
}
sphere(r=10, $fn=30);
}
//round3d(10)
$fn=20;
*minkowski() {
minkowski_difference() {
union() {
cylinder(120, d=100, center=true);
rotate([90, 0, 0]) cylinder(120, d=70, center=true);
rotate([0, 90, 0]) cylinder(120, d=70, center=true);
}
sphere(r=10);
}
sphere(r=5);
}
include<BOSL2/std.scad>
*minkowski() {
prismoid([50,50],[30,30],h=40)
position(RIGHT+TOP)
cube([15,15,25],orient=RIGHT,anchor=LEFT+BOT);
sphere(r=5, $fn=100);
}
include <BOSL2/std.scad>
dims=[100, 200, 30];
holes=[5, 10];
border=10;
smoothRadius=2;
smoothFn=$preview ? 5 : 30;
holeDiam=10;
holeFn=$preview ? 10 : 30;
minkowski()
{
union() {
difference() {
cube(dims);
translate([border, border, border])
cube(dims - 2 * [border, border, 0]);
for (i=[0:holes[0]], j=[0:holes[1]])
translate([
border + (i + 0.5) * (dims[0] - 2 * border) / (holes[0] + 1),
border + (j + 0.5) * (dims[1] - 2 * border) / (holes[1] + 1),
0
])
cylinder(h = border, d=holeDiam, $fn=holeFn);
}
}
sphere(smoothRadius, $fn=smoothFn);
}
$fn=60;
minkowski() {
difference() {
hull() {
translate([3, 0, 0]) cube(0.5, center=true);
cube(1, center=true);
}
translate([0, 0, 0])
sphere(1);
}
sphere(1);
}
// Baseline: 10m55s
// Baseline w/ fast-csg & trust: 1m20s (MBP M2 Max: 19s)
// This PR w/ fast-csg & trust: 35s
$fn=50;
minkowski()
{
cube([10,10,1]);
sphere(r=2,h=1);
}
translate([0,0,-2]) minkowski(){
union(){
cylinder(r=10+4, h = 2, $fn=400); // base
translate([0,0,-2]){ // image
cube([2,20,2], center = true);
cube([20,2,2], center = true);
}
}
cylinder(r1 = 0, r2 = 2, h = 2, $fn = 200); // bevel
}
translate([0,0,4]){ // handle
difference() {
cube([15,2,6], center = true);
translate([0,0,-1]) cube([10,3,4], center = true);
}
}
include <BOSL2/std.scad>
$fn=20;
minkowski() {
minkowski_difference() {
union() {
cylinder(120, d=100, center=true);
rotate([90, 0, 0]) cylinder(120, d=70, center=true);
rotate([0, 90, 0]) cylinder(120, d=70, center=true);
}
sphere(r=10);
}
sphere(r=5);
}
#!/bin/bash
# Copyright 2021 Google LLC.
# SPDX-License-Identifier: Apache-2.00
#
# Usage
# ./render (manifold|fastcsg|nef) file.scad [parameter-set-name]
#
set -euo pipefail
MODE="${1:?Mode not set. Pass manifold or fastcsg}"
INPUT_AND_PARAM_SET="${2:?Input file not set}"
INPUT="$( echo "$INPUT_AND_PARAM_SET" | sed -E 's/^(.*):.*$/\1/' )"
PARAM_SET="$( echo "$INPUT_AND_PARAM_SET" | sed -E 's/^[^:]*:?(.*)$/\1/' )"
OPENSCAD=${OPENSCAD:-$PWD/../openscad1/build/OpenSCAD.app/Contents/MacOS/OpenSCAD}
OUTPUT_DIR=${OUTPUT_DIR:-$PWD/out}
mkdir -p "$OUTPUT_DIR"
INPUT_NAME=$( basename "$INPUT" )
OUTPUT_PREFIX="${OUTPUT_DIR}/${INPUT_NAME%.scad}-${MODE}"
ARGS=(
"$INPUT"
--export-format=binstl
-o "$OUTPUT_PREFIX.stl"
)
if [[ -n "$PARAM_SET" ]]; then
ARGS+=(
-p "${INPUT%.scad}.json"
-P "$PARAM_SET"
)
fi
case "$MODE" in
manifold)
ARGS+=(
"--enable=manifold"
)
;;
fastcsg)
ARGS+=(
"--enable=fast-csg"
"--enable=fast-csg-exact"
"--enable=fast-csg-exact-callbacks"
"--enable=fast-csg-remesh"
"--enable=fast-csg-trust-corefinement"
)
;;
nef)
;;
*)
echo "Invalid mode: $MODE" >&2
exit 1
esac
$OPENSCAD "${ARGS[@]}" | tee "$OUTPUT_PREFIX.log"
{
"fileFormatVersion": "1",
"parameterSets": {
"N=2 $fn=20": {
"N": "2",
"$fn": "20"
},
"N=2 $fn=100": {
"N": "2",
"$fn": "100"
},
"N=10 $fn=20": {
"N": "10",
"$fn": "20"
},
"N=10 $fn=100": {
"N": "10",
"$fn": "100"
}
}
}
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
//
// Author: Olivier Chafik (http://ochafik.com)
//
// This is my little print-in-place chain/scalemail project where I wanted to be
// able to draw on each scale separately, or across all of them (3D printing of
// large etchings may work best with support material, but for small text it's
// fine).
//
// This is my little chain/scalemail project where I wanted to be able to draw on each
// scale separately. OpenSCAD was taking too much time to render this, so I began
// a rendering optimization crusade (toyed with multithreading, lazier unions, faster
// union algorithms), current result (Feb 14th 2021) being this model renders in
// 68sec instead of 6minutes (5x faster) for use_sweep = false,
// and 1.5sec instead of 39sec (27x faster) for use_sweep = true.
//
// To reproduce this speedup before those changes are upstreamed (if they are):
//
// openscad --enable=fast-union --enable=lazy-union --enable=lazy-module --enable=flatten-children --enable=push-transforms-down-unions scalemail.scad -o scalemail.stl
//
// Precision and thickness of curves
$fn=20;
step = 0.01;//$preview ? 0.01 : 0.001;
thickness = 0.6;
use_sweep = false;
// Just leave this empty to get each tile numbered individually.
global_text = "\u2665";
// Width & height of the grid. Model will have N*N tiles.
N = 2;
// Parameters of the torus knot
n=4;
m=1;
height = 1.5;
r1 = 2;
r2 = 3;
plate_fill = 1.2;
epsilon = 0.01;
stride = r1 + r2;
zScale = height / 2;
plate_thickness = thickness * 1.5;
extra_pillar_height = thickness;
avgRadius = (r1 + r2) / 2;
inner_pillar_end_ratio = 0.7;
text_etching_depth = plate_thickness / 2;
individual_text_size = 2;
global_text_size_factor = 0.8;
global_text_size = N * stride * global_text_size_factor;
plate_z = -zScale - thickness / 2 - plate_thickness - extra_pillar_height;
function f(t) = [
cos(m * t) * (avgRadius + (r2 - r1) / 2 * cos(n * t)),
sin(m * t) * (avgRadius + (r2 - r1) / 2 * cos(n * t)),
zScale * sin(n * t)
];
use <sweep.scad>
use <scad-utils/shapes.scad>
module draw_curve_sweep(p, thickness)
sweep(circle(thickness / 2), construct_transform_path(p), true);
module draw_curve(p, thickness)
if (use_sweep)
draw_curve_sweep(p, thickness);
else
for (i=[0:len(p)-2])
hull() {
translate(p[i]) sphere(d=thickness);
translate(p[i+1]) sphere(d=thickness);
}
module torus_knot() draw_curve([for (t=[0:step:1]) f(t * 360)], thickness);
module etching_text(size, text)
translate([0, 0, plate_z - epsilon])
linear_extrude(height = text_etching_depth)
mirror([-1, 0, 0])
text(text = text, size = size, valign = "center", halign="center");
module scalemail()
for (i=[0:N-1]) translate([i * stride,0,0])
for(j=[0:N-1]) translate([0,j * stride,0])
unit(global_text == "" ? str((N - j - 1) * N + (N - i - 1)) : undef);
if (global_text == "")
scalemail();
else
difference() {
scalemail();
translate([stride * N / 2 - stride / 2, stride * N / 2 - stride / 2, 0])
etching_text(global_text_size, global_text);
}
module unit(text) {
torus_knot();
// Draw the pillars from mid-height positions.
mid_param_offset = 360 / n / 2;
mid_angles = [for (i=[0:n-1]) i * 360/n + mid_param_offset];
mid_heights = [for (a=mid_angles) f(a)];
for (i=[0:n-1]) {
pillar_end = mid_heights[i];
angle = mid_angles[i];
hull() {
translate(pillar_end)
sphere(d=thickness);
translate([pillar_end[0], pillar_end[1], -zScale - thickness / 2 - extra_pillar_height])
cylinder(thickness / 2 + extra_pillar_height, d=thickness);
translate([inner_pillar_end_ratio * pillar_end[0], inner_pillar_end_ratio * pillar_end[1], -zScale - thickness / 2 - extra_pillar_height - plate_thickness])
cylinder(plate_thickness, d=thickness);
rotate([0, 0, (i + 0.5) * 360 / n])
translate([plate_fill * (avgRadius - thickness / 2), 0, -zScale - thickness / 2 - plate_thickness])
cylinder(h=plate_thickness, d=thickness);
}
}
difference() {
hull()
for (i=[0:n-1])
rotate([0, 0, (i + 0.5) * 360 / n])
translate([plate_fill * (avgRadius - thickness / 2), 0, plate_z])
cylinder(h=plate_thickness, d=thickness);
if (!is_undef(text)) etching_text(individual_text_size, text);
}
}
include <BOSL2/std.scad>
minkowski() {
diff("dish", keep="antenna")
cube(100, center=true)
attach([FRONT,TOP], overlap=33) {
tag("dish") cylinder(h=33.1, d1=0, d2=95, $fn=100);
tag("antenna") cylinder(h=33.1, d=10, $fn=100);
}
sphere(r=5, $fn=100);
}
include <BOSL2/std.scad>
$fn=$preview ? 15 : 30;
offset3d(1)
bottom_half()
difference() {
cube(10, center=true);
xscale(0.9) yscale(1.1)
sphere(d=10);
}
{
"fileFormatVersion": "1",
"parameterSets": {
"overlap=true": {
"overlap": "true"
},
"overlap=false": {
"overlap": "false"
}
}
}
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
N = 5;
// When this is true, we end up with lots of overlaps, which goes in the way of some optimizations but is still very fast with fast-csg
overlap = false;
// A simple grid of smooth spheres
union() {
for (i=[0:N-1], j=[0:N-1])
translate([i, j, 0])
sphere(d=(overlap ? 1.1 : 0.9), $fn=50);
}
{
"fileFormatVersion": "1",
"parameterSets": {
"overlap=true": {
"overlap": "true"
},
"overlap=false": {
"overlap": "false"
}
}
}
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.00
N = 3;
overlap = false;
union() {
for (i=[0:N-1]) translate([i,0,0])
for (j=[0:N-1]) translate([0,j,0])
sphere(d=(overlap ? 1.1 : 0.9), $fn=50);
}
{
"fileFormatVersion": "1",
"parameterSets": {
"overlap=true": {
"overlap": "true"
},
"overlap=false": {
"overlap": "false"
}
}
}
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
N = 3;
overlap = false;
union() {
for (i=[0:N-1], j=[0:N-1])
translate([i,j,0])
sphere(d=(overlap ? 1.1 : 0.9), $fn=50);
}
{
"fileFormatVersion": "1",
"parameterSets": {
"$fn=100": {
"$fn": "100"
},
"$fn=200": {
"$fn": "200"
},
"$fn=300": {
"$fn": "300"
},
"$fn=400": {
"$fn": "400"
}
}
}
// Author: https://github.com/gringer
// Origin: https://github.com/openscad/openscad/issues/356#issuecomment-29764897
$fn=30;
translate([0,0,-2]) minkowski(){
union(){
cylinder(r=10+4, h = 2); // base
translate([0,0,-2]){ // image
cube([2,20,2], center = true);
cube([20,2,2], center = true);
}
}
cylinder(r1 = 0, r2 = 2, h = 2); // bevel
}
translate([0,0,4]){ // handle
difference() {
cube([15,2,6], center = true);
translate([0,0,-1]) cube([10,3,4], center = true);
}
}
// Copyright 2021 Google LLC.
// SPDX-License-Identifier: Apache-2.0
top_transform = true;
top_union = true;
N = 5;
size = 2;
$fn=12;
module grid(N)
{
for (i=[0:N-1], j=[0:N-1]) translate([i * size, j * size, 0])
// for (i=[0:N-1]) translate([i * size, 0, 0]) for (j=[0:N-1]) translate([0, j * size, 0])
{
sphere(d=1, $fn=16);
difference() {
h = 1 + (i + N * j) / pow(N, 2);
hull() {
cube(h, center=true);
cylinder(h / 2 - 0.01, d=h * 1.3);
}
cylinder(h, r=0.45);
translate([0, 0.5, 0])
cylinder(h, r=0.2);
}
}
}
if (top_union)
union() {
if (top_transform)
translate([0, 0, 1])
grid(N);
else
grid(N);
}
else if (top_transform)
translate([0, 0, 1])
grid(N);
else
grid(N);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment