Compare commits

..

15 commits
trunk ... wip/5

Author SHA1 Message Date
djerun
83983d0bc5 [WIP] badge_test 2025-07-09 23:22:52 +02:00
user
b7fbdfe35d fixup! [WIP][DEBUG] 2025-07-09 21:25:52 +02:00
djerun
165c80b1d4 declutter catear_v3 2025-07-08 12:51:04 +02:00
user
d47be5dbc6 fine tune ear headband defaults as globals 2025-07-06 15:41:44 +02:00
djerun
da1d122947 [WIP] align chamfer 2025-06-28 01:41:42 +02:00
djerun
4c0d0ee417 foxear_headband: upgrade to ear version 3 2025-06-28 01:12:41 +02:00
djerun
840544a3d2 bunnyear_headband: upgrade to ear version 3 2025-06-28 01:12:04 +02:00
djerun
fdfdfd0d8d [WIP] 2025-06-28 01:09:28 +02:00
djerun
58fe834489 [WIP] add polyhedron-based catears 2025-06-27 09:00:23 +02:00
djerun
519a41c7a4 [WIP][DEBUG] 2025-06-15 16:30:38 +02:00
djerun
cfc13bbc13 fixup! [WIP] primitives library 2025-06-15 16:29:42 +02:00
djerun
05f2758275 [WIP] add additional ear shaping methods
v2: semi-circle remapped polyhedron

v3: bezier curve polyhedron
2025-06-15 16:19:36 +02:00
djerun
abab3a7b27 [WIP] primitives library 2025-06-15 14:58:41 +02:00
djerun
89a33df7ff [WIP] bottle tag logo 2024-12-14 14:31:52 +01:00
djerun
892899c511 [WIP] pressfit ears 2024-12-14 14:29:56 +01:00
16 changed files with 1584 additions and 89 deletions

4
badge_test.json Normal file
View file

@ -0,0 +1,4 @@
{
"parameterSets": "",
"fileFormatVersion": "1"
}

72
badge_test.scad Normal file
View file

@ -0,0 +1,72 @@
$fn=32;
LAYER_HEIGHT=1;
NAME="c6hex";
COLOR_BASE="#ffffff";
COLOR_LOGO="#7f7f7f";
COLOR_NAME="#7f7fff";
RENDER_BASE_COLOR=true;
RENDER_LOGO_COLOR=true;
RENDER_NAME_COLOR=true;
module name() {
translate([18, 4, 0]) text(NAME, font="Roboto:bold");
}
module logo() {
translate([10, 10])
scale([16, 16])
circle(d=1, $fn=6);
}
module name_outline() {
minkowski() {
name();
circle(r=2.5);
}
}
module logo_outline() {
minkowski() {
logo();
circle(r=2);
}
}
module outline() {
union() {
name_outline();
logo_outline();
}
}
module name_cutout() {
difference() {
outline();
name();
}
}
module logo_cutout() {
difference() {
name_cutout();
logo();
}
}
module name_cutout_plate() {
linear_extrude(height=LAYER_HEIGHT) name_cutout();
}
module logo_cutout_plate() {
linear_extrude(height=LAYER_HEIGHT) logo_cutout();
}
module name_base_plate() {
linear_extrude(height=LAYER_HEIGHT) outline();
}
if (RENDER_BASE_COLOR) color(COLOR_BASE) translate([0, 0, 3*LAYER_HEIGHT]) logo_cutout_plate();
if (RENDER_LOGO_COLOR) color(COLOR_LOGO) translate([0, 0, 2*LAYER_HEIGHT]) name_cutout_plate();
if (RENDER_NAME_COLOR) color(COLOR_NAME) translate([0, 0, 1*LAYER_HEIGHT]) name_base_plate();
if (RENDER_BASE_COLOR) color(COLOR_BASE) translate([0, 0, 0*LAYER_HEIGHT]) name_base_plate();

View file

@ -0,0 +1,32 @@
include <primitives.scad>;
a=90;
module circle_(r) {
c = 0.55191;
cp=[
[ 0, 1, 0], // 0
[ c, 1, 0], // 1
[ 1, c, 0], // 2
[ 1, 0, 0], // 3
[ 1, 0, 0], // 4
[ 1, -c, 0], // 5
[ c, -1, 0], // 6
[ 0, -1, 0], // 7
[ 0, -1, 0], // 8
[-c, -1, 0], // 9
[-1, -c, 0], // a
[-1, 0, 0], // b
[-1, 0, 0], // c
[-1, c, 0], // d
[-c, 1, 0], // e
[ 0, 1, 0] // f
];
for (i=[0:3]) {
control_points=[cp[i*4], cp[i*4+1], cp[i*4+2], cp[i*4+3]];
curve_vertices=bezier_curve_vertices(control_points*r, $fn);
render_curve(curve_vertices, width=2, height=2, chamfer=1, debug=false);
}
}
circle_(50);

View file

@ -1,7 +1,16 @@
use <catear_headband.scad>
include <headband.scad>
module bunnyear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKNESS, part=PART, stretch_len=STRETCH_LEN, tip_len=TIP_LEN, tip_bend=TIP_BEND, ear_scale=0.5, ear_bend_factor=0.2, ear_stretch_factor=8, ear_angle=30) {
EAR_VERSION = 3;
EAR_SKEW = 1;
EAR_SCALE = 0.5;
EAR_BEND_FACTOR = 1.0;
EAR_STRETCH_FACTOR = 8;
EAR_ANGLE = 30;
WITH_RAKE = true;
DETAILS = true;
module bunnyear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKNESS, part=PART, stretch_len=STRETCH_LEN, tip_len=TIP_LEN, tip_bend=TIP_BEND, ear_scale=EAR_SCALE, ear_bend_factor=EAR_BEND_FACTOR, ear_stretch_factor=EAR_STRETCH_FACTOR, ear_angle=EAR_ANGLE, ear_version=EAR_VERSION, ear_skew=EAR_SKEW) {
catear_headband(
debug=debug,
size=size,
@ -14,7 +23,9 @@ module bunnyear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKN
ear_scale=ear_scale,
ear_bend_factor=ear_bend_factor,
ear_stretch_factor=ear_stretch_factor,
ear_angle=ear_angle);
ear_angle=ear_angle,
ear_version=ear_version,
ear_skew=ear_skew);
}
bunnyear_headband();
rotate(-90) bunnyear_headband();

View file

@ -61,7 +61,7 @@ USE_TINY_EARS = true;
*/
scale([0.2, 0.2, 0.2]) {
difference() {
scale([5, 5, 5]) rotate(45, [0, 0, 1]) bottle_clip(name=NAME);
scale([5, 5, 5]) rotate(45, [0, 0, 1]) bottle_clip(name=NAME, logo=LOGO_FILE);
translate([ 15*5, 0*5, 18*5]) rotate(80, [0, 1, 0]) catear();
translate([-15*5, 0*5, 18*5]) rotate(-80, [0, 1, 0]) catear();
}
@ -93,6 +93,7 @@ module name(name, font, rl, ht, ru) {
module logo(logo, rl, ht, ru, width) {
echo("logo: ", logo);
if(logo == "") {
echo("CATEAR LOGO");
ear_size=ht;
echo("ht: ", ht);
echo("ru: ", ru);
@ -114,32 +115,29 @@ module logo(logo, rl, ht, ru, width) {
with_rake=false
);
} else {
echo("LOGO: ", logo);
// The logo has been split in 3 parts. // well was... TODO
/*
rotate([0,0,-48]) translate([0,0,ht*3/4-0.1])
rotate([0,0,-45]) translate([0,0,ht*3/4-0.1])
rotate([90,0,0])
scale([0.9,0.9,1])
scale([0.8,0.8,1])
scale([ht/100,ht/100,1])
translate([-25,-29,0.5])
translate([-32,-33,0.5])
linear_extrude(height=max(ru,rl)*2)
import("logo_1.dxf");
*/
import("test.svg");
translate([0,0,ht*3/4-0.1])
rotate([90,0,0])
scale([0.8,0.8,1])
scale([ht/100,ht/100,1])
translate([-18,-22,0.5])
translate([-32,-33,0.5])
linear_extrude(height=max(ru,rl)*2)
import(logo);
/*
rotate([0,0,44]) translate([0,0,ht*3/4-0.1])
rotate([0,0,45]) translate([0,0,ht*3/4-0.1])
rotate([90,0,0])
scale([0.7,0.7,1])
scale([0.8,0.8,1])
scale([ht/100,ht/100,1])
translate([-25,-26,0.5])
translate([-32,-33,0.5])
linear_extrude(height=max(ru,rl)*2)
import("logo_3.dxf");
*/
import("test.svg");
}
}
@ -153,7 +151,7 @@ module bottle_clip(ru=13, rl=17.5, ht=26, width=2.5, name="c3cat", font="write/o
difference() {
union() {
name(name=name, font=font, rl=rl, ht=ht, ru=ru);
logo(logo=logo, rl=rl, ht=ht, ru=ru, width=width);
logo(logo=logo, rl=rl, ht=ht, ru=ru, width=2*width);
}
cylinder(r1=rl+width/2, r2=ru+width/2, h=ht);
}

View file

@ -0,0 +1,910 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64mm"
height="64mm"
id="svg2"
sodipodi:version="0.32"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="sterntastatur.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
class="TridactylThemeDark"
version="1.1"
viewBox="0 0 226.77166 226.77167"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<defs
id="defs4">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : -184.8189 : 1"
inkscape:vp_y="0 : 1066.6668 : 0"
inkscape:vp_z="793.70077 : -184.8189 : 1"
inkscape:persp3d-origin="396.85039 : -371.90552 : 1"
id="perspective10" />
<inkscape:perspective
id="perspective2447"
inkscape:persp3d-origin="396.85039 : -371.90552 : 1"
inkscape:vp_z="793.70077 : -184.8189 : 1"
inkscape:vp_y="0 : 1066.6668 : 0"
inkscape:vp_x="0 : -184.8189 : 1"
sodipodi:type="inkscape:persp3d" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="10000"
guidetolerance="10"
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2"
inkscape:cx="98.5"
inkscape:cy="100"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1920"
inkscape:window-height="1035"
inkscape:window-x="0"
inkscape:window-y="22"
inkscape:showpageshadow="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:window-maximized="1">
<sodipodi:guide
orientation="1,0"
position="1638.0953,-228.02731"
id="guide3559"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata7">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-11.630257,-173.89075)">
<path
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 124.63977,336.54091 -58.001141,43.35048 13.626759,-42.5247 h -6.256877 l -18.860883,58.84873 69.477402,-51.9401 70.67062,51.71951 -19.45247,-58.62814 h -6.28696 l 14.04789,42.34422 z m 0.24596,-158.20317 -25.970036,83.25457 -87.285434,0.11025 13.265772,9.54575 h 10.448189 l -5.033584,-3.61977 72.856523,-0.0902 21.66843,-69.48744 22.59094,69.46682 72.15462,-0.18995 -27.08305,19.91371 h 10.68883 l 35.21498,-25.89986 -86.44316,0.32031 z"
id="path3555"
sodipodi:nodetypes="cccccccccccccccccccccccccc" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect2461"
width="7.778954"
height="8.2651386"
x="29.938887"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3233"
width="7.778954"
height="8.2651386"
x="46.307102"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3235"
width="7.778954"
height="8.2651386"
x="55.004387"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3237"
width="7.778954"
height="8.2651386"
x="63.701714"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3239"
width="7.778954"
height="8.2651386"
x="72.399002"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3241"
width="7.778954"
height="8.2651386"
x="83.824341"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3243"
width="7.778954"
height="8.2651386"
x="92.521629"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3245"
width="7.778954"
height="8.2651386"
x="101.21893"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3247"
width="7.778954"
height="8.2651386"
x="109.91624"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3249"
width="7.778954"
height="8.2651386"
x="121.74675"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3251"
width="7.778954"
height="8.2651386"
x="130.44405"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3253"
width="7.778954"
height="8.2651386"
x="139.14133"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3255"
width="7.778954"
height="8.2651386"
x="147.83865"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3257"
width="7.778954"
height="8.2651386"
x="159.50708"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3259"
width="7.778954"
height="8.2651386"
x="168.20438"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3261"
width="7.778954"
height="8.2651386"
x="176.9017"
y="274.89148"
ry="1.4585506" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3265"
width="7.3783197"
height="7.461844"
x="159.80417"
y="291.61737"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3267"
width="7.3783293"
height="7.461844"
x="168.05357"
y="291.61737"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3269"
width="7.3783197"
height="7.461844"
x="176.22189"
y="291.61737"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3271"
width="7.321022"
height="7.3913627"
x="160.08084"
y="300.09735"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3273"
width="7.321022"
height="7.3913627"
x="168.33022"
y="300.09735"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3275"
width="7.3783197"
height="7.3913627"
x="176.57959"
y="300.09735"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3277"
width="6.9686465"
height="7.4041867"
x="38.852264"
y="291.70407"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3279"
width="6.9686465"
height="7.4041867"
x="47.238949"
y="291.70416"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3281"
width="6.9686465"
height="7.4041867"
x="55.625633"
y="291.70416"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3283"
width="6.9686465"
height="7.4041867"
x="64.012314"
y="291.70416"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3285"
width="6.9686465"
height="7.4041867"
x="72.399002"
y="291.70416"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3287"
width="6.9686465"
height="7.4041867"
x="80.785675"
y="291.70416"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3289"
width="6.9686465"
height="7.4041867"
x="89.172363"
y="291.70416"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3291"
width="6.9686465"
height="7.4041867"
x="97.559044"
y="291.70416"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3293"
width="6.9686465"
height="7.4041867"
x="105.94573"
y="291.70416"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3295"
width="6.9686465"
height="7.4041867"
x="114.33241"
y="291.70416"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3297"
width="6.9686465"
height="7.4041867"
x="122.7191"
y="291.70416"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3299"
width="6.9686465"
height="7.4041867"
x="131.10579"
y="291.70416"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3301"
width="6.9686465"
height="7.4041867"
x="42.88353"
y="300.12665"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3303"
width="6.9686465"
height="7.4041867"
x="51.270214"
y="300.1022"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3305"
width="6.9686465"
height="7.4041867"
x="59.656898"
y="300.1022"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3307"
width="6.9686465"
height="7.4041867"
x="68.043579"
y="300.1022"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3309"
width="6.9686465"
height="7.4041867"
x="76.43026"
y="300.1022"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3311"
width="6.9686465"
height="7.4041867"
x="84.81694"
y="300.1022"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3313"
width="6.9686465"
height="7.4041867"
x="93.203629"
y="300.1022"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3315"
width="6.9686465"
height="7.4041867"
x="101.59031"
y="300.1022"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3317"
width="6.9686465"
height="7.4041867"
x="109.97699"
y="300.1022"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3319"
width="6.9686465"
height="7.4041867"
x="118.36369"
y="300.1022"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3321"
width="6.9686465"
height="7.4041867"
x="126.75037"
y="300.1022"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3323"
width="6.9686465"
height="7.4041867"
x="135.13705"
y="300.1022"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3325"
width="6.9686465"
height="7.4041867"
x="44.828308"
y="308.54919"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3327"
width="6.9686465"
height="7.4041867"
x="53.214951"
y="308.52939"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3329"
width="6.9686465"
height="7.4041867"
x="61.601635"
y="308.52939"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3331"
width="6.9686465"
height="7.4041867"
x="69.988319"
y="308.52939"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3333"
width="6.9686465"
height="7.4041867"
x="78.375"
y="308.52939"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3335"
width="6.9686465"
height="7.4041867"
x="86.761681"
y="308.52939"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3337"
width="6.9686465"
height="7.4041867"
x="95.148361"
y="308.52939"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3339"
width="6.9686465"
height="7.4041867"
x="103.53505"
y="308.52939"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3341"
width="6.9686465"
height="7.4041867"
x="111.92173"
y="308.52939"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3343"
width="6.9686465"
height="7.4041867"
x="120.30843"
y="308.52939"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3345"
width="6.9686465"
height="7.4041867"
x="128.69508"
y="308.52939"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3349"
width="6.9686465"
height="7.4041867"
x="49.203938"
y="316.97177"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3351"
width="6.9686465"
height="7.4041867"
x="57.590622"
y="316.97177"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3353"
width="6.9686465"
height="7.4041867"
x="65.977303"
y="316.97177"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3355"
width="6.9686465"
height="7.4041867"
x="74.363983"
y="316.97177"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3357"
width="6.9686465"
height="7.4041867"
x="82.750664"
y="316.97177"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3359"
width="6.9686465"
height="7.4041867"
x="91.137352"
y="316.97177"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3361"
width="6.9686465"
height="7.4041867"
x="99.524033"
y="316.97177"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3363"
width="6.9686465"
height="7.4041867"
x="107.91072"
y="316.97177"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3365"
width="6.9686465"
height="7.4041867"
x="116.2974"
y="316.97177"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3367"
width="6.9686465"
height="7.4041867"
x="124.68409"
y="316.97177"
ry="1.3066182" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3373"
width="7.3783216"
height="7.778954"
x="189.24539"
y="291.61737"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3375"
width="7.3783216"
height="7.778954"
x="197.40019"
y="291.57684"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3377"
width="7.3783216"
height="7.778954"
x="205.55504"
y="291.57684"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3379"
width="7.3783216"
height="7.778954"
x="189.24539"
y="299.93683"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3381"
width="7.3783216"
height="7.778954"
x="197.41371"
y="299.90979"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3383"
width="7.3783216"
height="7.778954"
x="205.58208"
y="299.90979"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3385"
width="7.3783216"
height="7.778954"
x="189.24539"
y="308.25623"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3387"
width="7.3783216"
height="7.778954"
x="197.40388"
y="308.24274"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3389"
width="7.3783216"
height="7.778954"
x="205.56241"
y="308.24274"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3391"
width="7.3783216"
height="7.778954"
x="189.23802"
y="316.57568"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3393"
width="7.3783216"
height="7.778954"
x="197.39656"
y="316.57568"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3395"
width="7.3783216"
height="7.778954"
x="205.55504"
y="316.57568"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3397"
width="7.2262039"
height="7.6778531"
x="214.01192"
y="291.61737"
ry="1.3430512" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3401"
width="7.3783216"
height="7.778954"
x="168.29529"
y="315.94006"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3403"
width="7.3783216"
height="7.778954"
x="168.29529"
y="324.96848"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3405"
width="7.3783216"
height="7.778954"
x="176.54613"
y="324.96848"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3407"
width="7.3783216"
height="7.778954"
x="160.04446"
y="324.96848"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3409"
width="7.3783221"
height="7.4143133"
x="30.139193"
y="291.66492"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3411"
width="11.25044"
height="7.3913627"
x="30.100925"
y="300.09735"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3413"
width="13.291304"
height="7.3913674"
x="30.100925"
y="308.54874"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3415"
width="17.509472"
height="7.3893433"
x="30.100925"
y="316.97144"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3417"
width="11.346565"
height="7.3738036"
x="30.100925"
y="325.37366"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3419"
width="11.267799"
height="7.3738012"
x="51.693386"
y="325.37366"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3421"
width="11.392224"
height="7.3738012"
x="122.10909"
y="325.37366"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3423"
width="11.062954"
height="7.3738012"
x="143.01506"
y="325.37366"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3425"
width="10.647362"
height="7.4090323"
x="143.47343"
y="300.09735"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3427"
width="17.16914"
height="7.3848572"
x="136.95163"
y="308.54874"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3429"
width="21.106087"
height="7.334084"
x="133.01468"
y="317.04187"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3431"
width="14.672773"
height="7.4416533"
x="139.44801"
y="291.62433"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3433"
width="15.484227"
height="7.3738012"
x="189.23802"
y="325.37366"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3437"
width="7.1352501"
height="16.125122"
x="214.09291"
y="299.849"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3439"
width="56.482964"
height="7.3738012"
x="64.33416"
y="325.37366"
ry="1.3727535" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3441"
width="7.0459976"
height="16.20615"
x="214.19212"
y="316.54129"
ry="1.3727535"
inkscape:label="rect3441" />
<rect
style="fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:0.641731;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect3447"
width="7.356194"
height="7.3738012"
x="205.53864"
y="325.37366"
ry="1.3727535"
inkscape:label="rect3447" />
</g>
<xhtml:iframe
class="cleanslate hidden"
src="sterntastatur_files/commandline.html"
id="cmdline_iframe"
loading="lazy"
style="height: 0px !important;" />
</svg>

After

Width:  |  Height:  |  Size: 38 KiB

View file

@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="64mm"
height="64mm"
viewBox="0 0 64 64"
version="1.1"
id="svg1"
inkscape:version="1.4 (e7c3feb100, 2024-10-09)"
sodipodi:docname="test.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:showpageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="mm"
inkscape:zoom="3"
inkscape:cx="119"
inkscape:cy="116.33333"
inkscape:window-width="1920"
inkscape:window-height="1035"
inkscape:window-x="0"
inkscape:window-y="22"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
id="rect1"
style="fill:#800080;stroke-width:0.264583"
d="M 0 0 L 0 16.000057 L 11.999784 16.000057 L 11.999784 27.999841 L 24.000085 27.999841 L 24.000085 35.99987 L 11.999784 35.99987 L 11.999784 48.000171 L 0 48.000171 L 0 64.000228 L 16.000057 64.000228 L 16.000057 51.999927 L 27.999841 51.999927 L 27.999841 40.000142 L 35.99987 40.000142 L 35.99987 51.999927 L 48.000171 51.999927 L 48.000171 64.000228 L 64.000228 64.000228 L 64.000228 48.000171 L 51.999927 48.000171 L 51.999927 35.99987 L 40.000142 35.99987 L 40.000142 27.999841 L 51.999927 27.999841 L 51.999927 16.000057 L 64.000228 16.000057 L 64.000228 0 L 48.000171 0 L 48.000171 11.999784 L 35.99987 11.999784 L 35.99987 24.000085 L 27.999841 24.000085 L 27.999841 11.999784 L 16.000057 11.999784 L 16.000057 0 L 0 0 z " />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,9 +1,75 @@
include <globals.scad>;
include <primitives.scad>;
use <headband.scad>;
use <chamfer.scad>;
module catear(height, thickness, fractal=0, side_len=30, bend_factor=0.5, stretch_factor=1.2, debug=false, chamfer=CHAMFER, chamfer_shape=CHAMFER_SHAPE, details=true) {
EAR_VERSION = 3;
EAR_SKEW = 0.6;
EAR_SCALE = 1.4;
EAR_BEND_FACTOR = 0.04;
EAR_STRETCH_FACTOR = 1.2;
EAR_ANGLE = 42;
WITH_RAKE = true;
DETAILS = true;
catear_v3_control_points = function (S, sf, bf, mn, a) let (s=S/2, R=rotation_matrix(a)) [
[ s , 0, 0],
[ S*bf, S*sf*mn, 0] * R,
[-S*bf, S*sf*mn, 0] * R,
[-s , 0, 0],
];
/**
* unsupported parameters: chamfer, chamfer_shape, details, end_caps
*/
module catear_v3(height, thickness, fractal=0, side_len=30, bend_factor=0.15, stretch_factor=1.2, debug=false, chamfer=CHAMFER, chamfer_shape=CHAMFER_SHAPE, details=true, end_caps=true, skew=2.0, $fn=$fn) {
control_points = catear_v3_control_points(
S=side_len,
sf=stretch_factor,
bf=bend_factor,
mn=1.16,
a=skew*10
);
curve_vertices = bezier_curve_vertices(control_points, $fn);
if (debug) {
translate([0, 0, 2*height]) rotate(90) bezier_curve_debug(control_points);
echo("curve_vertices: ", curve_vertices);
}
rotate(90) render_curve(
curve_vertices,
width=thickness,
height=height,
chamfer=chamfer,
debug=debug
);
}
/**
* unsupported parameters: debug, chamfer, chamfer_shape, details, end_caps
*/
module catear_v2(height, thickness, fractal=0, side_len=30, bend_factor=0.15, stretch_factor=1.2, debug=false, chamfer=CHAMFER, chamfer_shape=CHAMFER_SHAPE, details=true, end_caps=true, skew=2.0) {
r=side_len/2;
T=side_len+thickness;
S=side_len-thickness;
x_stretch = function (x) pow(x, abs(skew));
y_stretch = function (y) pow(y, 2.0);
E=1.6*stretch_factor;
a=y_stretch(r)+thickness/2;
b=y_stretch(r)-thickness/2;
e=(E*a-thickness)/b;
echo("E",E,"e",e, "a", a, "b", b, "c", thickness);
outer_remap = function (p) [scalc(x_stretch, p.x, T/2, -T/2)*sign(skew), scalc(y_stretch, p.y, 0, T/2)*E, p.z];
inner_remap = function (p) [scalc(x_stretch, p.x, S/2, -S/2)*sign(skew), scalc(y_stretch, p.y, 0, T/2)*e, p.z];
or = function (p) [p.x, 2*p.y, p.z];
arc(0.5, r, thickness, height, outer_remap=outer_remap, inner_remap=inner_remap);
}
/**
* unsupported parameters: skew
*/
module catear_v1(height, thickness, fractal=0, side_len=30, bend_factor=0.15, stretch_factor=1.2, debug=false, chamfer=CHAMFER, chamfer_shape=CHAMFER_SHAPE, details=true, end_caps=true, skew=2.0) {
$A=[0, side_len/2];
$B=[0,-side_len/2];
$C=[-(side_len/2/sin(120))*1.5*stretch_factor, 0];
@ -42,15 +108,17 @@ module catear(height, thickness, fractal=0, side_len=30, bend_factor=0.5, stretc
thickness=thickness,
height=height
);
translate($A) color("#aaaaaa")
chamfer(size=chamfer, child_h=height, child_bot=-height/2, shape=chamfer_shape)
cylinder(h=height, d=thickness, center=true);
translate($B) color("#bbbbbb")
chamfer(size=chamfer, child_h=height, child_bot=-height/2, shape=chamfer_shape)
cylinder(h=height, d=thickness, center=true);
translate($C) color("#cccccc")
chamfer(size=chamfer, child_h=height, child_bot=-height/2, shape=chamfer_shape)
cylinder(h=height, d=thickness, center=true);
if (end_caps) {
translate($A) color("#aaaaaa")
chamfer(size=chamfer, child_h=height, child_bot=-height/2, shape=chamfer_shape)
cylinder(h=height, d=thickness, center=true);
translate($B) color("#bbbbbb")
chamfer(size=chamfer, child_h=height, child_bot=-height/2, shape=chamfer_shape)
cylinder(h=height, d=thickness, center=true);
translate($C) color("#cccccc")
chamfer(size=chamfer, child_h=height, child_bot=-height/2, shape=chamfer_shape)
cylinder(h=height, d=thickness, center=true);
}
if (debug) {
echo("A", $A, "a", $a, "alpha", $alpha);
@ -74,38 +142,102 @@ module catear(height, thickness, fractal=0, side_len=30, bend_factor=0.5, stretc
}
}
module catear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKNESS, part=PART, stretch_len=STRETCH_LEN, tip_len=TIP_LEN, tip_bend=TIP_BEND, ear_scale=1.5, ear_bend_factor=0.15, ear_stretch_factor=1.2, ear_angle=42, chamfer=CHAMFER, chamfer_shape=CHAMFER_SHAPE, with_rake=true, details=true) {
module catear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKNESS, part=PART, stretch_len=STRETCH_LEN, tip_len=TIP_LEN, tip_bend=TIP_BEND, ear_scale=EAR_SCALE, ear_bend_factor=EAR_BEND_FACTOR, ear_stretch_factor=EAR_STRETCH_FACTOR, ear_angle=EAR_ANGLE, chamfer=CHAMFER, chamfer_shape=CHAMFER_SHAPE, with_rake=WITH_RAKE, details=DETAILS, ear_skew=EAR_SKEW, ear_version=EAR_VERSION) {
$a=size/2*ear_scale;
$delta=2*(acos($a/(size*2))-90);
ear_offset=size*sin(90-$delta/2);
union() {
rotate( ear_angle, [0, 0, 1]) {
translate([-ear_offset, 0, 0]) catear(
debug=debug,
height=height,
thickness=thickness,
side_len=size/2*ear_scale,
bend_factor=ear_bend_factor,
stretch_factor=ear_stretch_factor,
chamfer=chamfer,
chamfer_shape=chamfer_shape,
details=details
);
if (ear_version == 3 ) {
rotate( ear_angle, [0, 0, 1]) {
translate([-ear_offset, 0, 0]) catear_v3(
debug=debug,
height=height,
thickness=thickness,
side_len=size/2*ear_scale,
bend_factor=ear_bend_factor,
stretch_factor=ear_stretch_factor,
chamfer=chamfer,
chamfer_shape=chamfer_shape,
details=details,
skew=ear_skew
);
}
rotate(-ear_angle, [0, 0, 1]) {
translate([-ear_offset, 0, 0]) catear_v3(
debug=false,
height=height,
thickness=thickness,
side_len=size/2*ear_scale,
bend_factor=ear_bend_factor,
stretch_factor=ear_stretch_factor,
chamfer=chamfer,
chamfer_shape=chamfer_shape,
details=details,
skew=-ear_skew
);
}
}
rotate(-ear_angle, [0, 0, 1]) {
translate([-ear_offset, 0, 0]) catear(
debug=false,
height=height,
thickness=thickness,
side_len=size/2*ear_scale,
bend_factor=ear_bend_factor,
stretch_factor=ear_stretch_factor,
chamfer=chamfer,
chamfer_shape=chamfer_shape,
details=details
);
if (ear_version == 2 ) {
rotate( ear_angle, [0, 0, 1]) {
translate([-ear_offset, 0, 0]) catear_v2(
debug=debug,
height=height,
thickness=thickness,
side_len=size/2*ear_scale,
bend_factor=ear_bend_factor,
stretch_factor=ear_stretch_factor,
chamfer=chamfer,
chamfer_shape=chamfer_shape,
details=details,
skew=ear_skew
);
}
rotate(-ear_angle, [0, 0, 1]) {
translate([-ear_offset, 0, 0]) catear_v2(
debug=false,
height=height,
thickness=thickness,
side_len=size/2*ear_scale,
bend_factor=ear_bend_factor,
stretch_factor=ear_stretch_factor,
chamfer=chamfer,
chamfer_shape=chamfer_shape,
details=details,
skew=-ear_skew
);
}
}
if (ear_version == 1 ) {
rotate( ear_angle, [0, 0, 1]) {
translate([-ear_offset, 0, 0]) catear_v1(
debug=debug,
height=height,
thickness=thickness,
side_len=size/2*ear_scale,
bend_factor=ear_bend_factor,
stretch_factor=ear_stretch_factor,
chamfer=chamfer,
chamfer_shape=chamfer_shape,
details=details,
skew=ear_skew
);
}
rotate(-ear_angle, [0, 0, 1]) {
translate([-ear_offset, 0, 0]) catear_v1(
debug=false,
height=height,
thickness=thickness,
side_len=size/2*ear_scale,
bend_factor=ear_bend_factor,
stretch_factor=ear_stretch_factor,
chamfer=chamfer,
chamfer_shape=chamfer_shape,
details=details,
skew=-ear_skew
);
}
}
headband(
size=size,
@ -121,4 +253,4 @@ module catear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKNES
};
}
catear_headband();
rotate(-90) catear_headband();

View file

@ -1,7 +1,16 @@
use <catear_headband.scad>
include <headband.scad>
module foxear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKNESS, part=PART, stretch_len=STRETCH_LEN, tip_len=TIP_LEN, tip_bend=TIP_BEND, ear_scale=1.2, ear_bend_factor=0.05, ear_stretch_factor=1.2, ear_angle=30) {
EAR_VERSION = 3;
EAR_SKEW = 1;
EAR_SCALE = 1.2;
EAR_BEND_FACTOR = 0.00;
EAR_STRETCH_FACTOR = 1.2;
EAR_ANGLE = 30;
WITH_RAKE = true;
DETAILS = true;
module foxear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKNESS, part=PART, stretch_len=STRETCH_LEN, tip_len=TIP_LEN, tip_bend=TIP_BEND, ear_scale=EAR_SCALE, ear_bend_factor=EAR_BEND_FACTOR, ear_stretch_factor=EAR_STRETCH_FACTOR, ear_angle=EAR_ANGLE, ear_version=EAR_VERSION, ear_skew=EAR_SKEW) {
catear_headband(
debug=debug,
size=size,
@ -14,7 +23,9 @@ module foxear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKNES
ear_scale=ear_scale,
ear_bend_factor=ear_bend_factor,
ear_stretch_factor=ear_stretch_factor,
ear_angle=ear_angle);
ear_angle=ear_angle,
ear_version=ear_version,
ear_skew=ear_skew);
}
foxear_headband();
rotate(-90) foxear_headband();

View file

@ -11,6 +11,10 @@ FN=90
NAME="\"$1\""
if [[ $# -ge 2 ]];then
LOGO_FILE="\"$2\""
fi
# usage: render NAME PART
render() {
case "$2" in

View file

@ -12,8 +12,8 @@ RAKE_WIDTH=1;
RAKE_STRETCH=1;
RAKE_CHAMFER=0.5;
CHAMFER=1;
CHAMFER_SHAPE="curve";
CHAMFER_SHAPE="cone";
INSERTICLE_X = 4.6;
INSERTICLE_Y = 7.4;
INSERTICLE_Z = 5.4;
INSERTICLE_Z = 5.4;

View file

@ -1,13 +1,7 @@
include <globals.scad>
include <primitives.scad>
use <chamfer.scad>
module partial_ring(part, radius, thickness, height) {
rotate(180-180*part, [0, 0, 1])
rotate_extrude(angle=360*part)
translate([radius, 0])
square([thickness, height], center=true);
}
module headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKNESS, part=PART, stretch_len=STRETCH_LEN, tip_len=TIP_LEN, tip_bend=TIP_BEND, rake_depth=RAKE_DEPTH, rake_width=RAKE_WIDTH, rake_stretch=RAKE_STRETCH, rake_chamfer=RAKE_CHAMFER, chamfer=CHAMFER, chamfer_shape=CHAMFER_SHAPE, with_rake=true, details=true) {
union() {
chamfer(size=(details)?chamfer:0, child_h=height, child_bot=-height/2, shape=chamfer_shape) union() {

View file

@ -1,7 +1,16 @@
use <catear_headband.scad>
include <headband.scad>
module mouseear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKNESS, part=PART, stretch_len=STRETCH_LEN, tip_len=TIP_LEN, tip_bend=TIP_BEND, ear_scale=1, ear_bend_factor=0.65, ear_stretch_factor=1, ear_angle=40) {
EAR_VERSION = 3;
EAR_SKEW = 0;
EAR_SCALE = 1;
EAR_BEND_FACTOR = 0.5;
EAR_STRETCH_FACTOR = 1;
EAR_ANGLE = 40;
WITH_RAKE = true;
DETAILS = true;
module mouseear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKNESS, part=PART, stretch_len=STRETCH_LEN, tip_len=TIP_LEN, tip_bend=TIP_BEND, ear_scale=EAR_SCALE, ear_bend_factor=EAR_BEND_FACTOR, ear_stretch_factor=EAR_STRETCH_FACTOR, ear_angle=EAR_ANGLE) {
catear_headband(
debug=debug,
size=size,
@ -17,4 +26,4 @@ module mouseear_headband(debug=DEBUG, size=SIZE, height=HEIGHT, thickness=THICKN
ear_angle=ear_angle);
}
mouseear_headband();
rotate(-90) mouseear_headband();

46
pressfit_bunnyears.scad Normal file
View file

@ -0,0 +1,46 @@
include <globals.scad>;
use <catear_headband.scad>;
use <pressfit_headband.scad>;
use <chamfer.scad>;
$fn=90;
EAR_SCALE = 0.5;
EAR_BEND_FACTOR = 0.2;
EAR_STRETCH_FACTOR = 8;
STEP_SIZE = .25;
module loop(i) {
j=pow(0.99, i);
//chamfer_ = floor(abs(2*i/(SIZE/2*EAR_SCALE-1)-1));
translate([-j*20, 0, 0])
difference() {
rotate(90, [0, 1, 0])
/*chamfer(size=1, child_h=1, child_bot=-0.5, shape=CHAMFER_SHAPE)*/ {
//echo("i", i, "j", j, "chamfer_", chamfer_);
union() catear(
debug=DEBUG,
height=INSERTICLE_Z*1.2,
thickness=THICKNESS,
side_len=SIZE/2*EAR_SCALE-i,
bend_factor=EAR_BEND_FACTOR,
stretch_factor=EAR_STRETCH_FACTOR,
chamfer=0, //chamfer_,
chamfer_shape=CHAMFER_SHAPE,
details=false,
end_caps=true
);
}
cube([100, 100, THICKNESS], center=true);
}
}
//difference() {
translate([20*pow(0.99, SIZE/2*EAR_SCALE-1-THICKNESS), 0, -THICKNESS/2])
union() for (i=[0:STEP_SIZE:0/*SIZE/2*EAR_SCALE-1*/]) {
loop(i);
}
// translate([0, 0, -THICKNESS]) cube([100, 100, THICKNESS], center=true);
// scale([1, 1, 2]) inserticle();
//}

View file

@ -1,5 +1,7 @@
include <globals.scad>;
include <primitives.scad>;
use <headband.scad>;
use <catear_headband.scad>;
use <pressfit_headband.scad>;
use <chamfer.scad>;
@ -7,26 +9,62 @@ use <chamfer.scad>;
EAR_SCALE = 1.5;
EAR_BEND_FACTOR = 0.15;
EAR_STRETCH_FACTOR = 1.2;
STEP_SIZE = 100;
difference() {
translate([20*pow(0.99, SIZE/2*EAR_SCALE-1-THICKNESS), 0, -THICKNESS/2])
union() for (i=[0:SIZE/2*EAR_SCALE-1]) {
j=pow(0.99, i);
chamfer_ = floor(abs(2*i/(SIZE/2*EAR_SCALE-1)-1));
translate([-j*20, 0, 0])
rotate(90, [0, 1, 0])
/*chamfer(size=1, child_h=1, child_bot=-0.5, shape=CHAMFER_SHAPE)*/
catear(
debug=DEBUG,
height=INSERTICLE_Z*1.2,
thickness=THICKNESS,
side_len=SIZE/2*EAR_SCALE-i,
bend_factor=EAR_BEND_FACTOR,
stretch_factor=EAR_STRETCH_FACTOR,
chamfer=chamfer_,
chamfer_shape=CHAMFER_SHAPE
);
translate([50, 0, 0]) difference() {
translate([20*pow(0.99, SIZE/2*EAR_SCALE-1-THICKNESS), 0, -THICKNESS/2])
union() for (i=[0:STEP_SIZE:SIZE/2*EAR_SCALE-1]) {
j=pow(0.99, i);
chamfer_ = floor(abs(2*i/(SIZE/2*EAR_SCALE-1)-1));
translate([-j*20, 0, 0])
rotate(90, [0, 1, 0])
/*chamfer(size=1, child_h=1, child_bot=-0.5, shape=CHAMFER_SHAPE)*/
catear_v1(
debug=DEBUG,
height=INSERTICLE_Z*1.2,
thickness=THICKNESS,
side_len=SIZE/2*EAR_SCALE-i,
bend_factor=EAR_BEND_FACTOR,
stretch_factor=EAR_STRETCH_FACTOR,
chamfer=0, //chamfer_,
chamfer_shape=CHAMFER_SHAPE,
end_caps=false
);
}
translate([0, 0, -THICKNESS]) cube([100, 100, THICKNESS], center=true);
scale([1, 1, 2]) inserticle();
}
translate([0, 0, -THICKNESS]) cube([100, 100, THICKNESS], center=true);
scale([1, 1, 2]) inserticle();
}
side_len=SIZE/2*EAR_SCALE;
r=side_len/2;
E=1.6*EAR_STRETCH_FACTOR;
e=E*(r+THICKNESS/4)/(r-THICKNESS/4);
T=side_len+THICKNESS;
S=side_len-THICKNESS;
xremap = function (x) pow(x, EAR_STRETCH_FACTOR);
yremap = function (y) pow(y, 1);
//f = function (p) [j((p.x+T/2)/T)*T-T/2, pow(p.y, 2)/r*E, p.z];
//g = function (p) [j((p.x+S/2)/S)*S-S/2, pow(p.y, 2)/r*E*(T+THICKNESS)/S, p.z];
f = function (p) [scalc(xremap, p.x, -T/2, T/2), scalc(yremap, p.y, 0, T/2)*E, p.z];
g = function (p) [scalc(xremap, p.x, -S/2, S/2), scalc(yremap, p.y, 0, S/2)*e, p.z];
rotate([0, 90, 0]) color("yellow") arc(0.5, r, THICKNESS, HEIGHT, outer_remap=f, inner_remap=g);
color("red") catear_v2(
height=HEIGHT,
thickness=THICKNESS,
side_len=SIZE/2*EAR_SCALE,
stretch_factor=EAR_STRETCH_FACTOR
);
// a = b + c
// x * a = y * b + c
// y * b = x * a - c
// y =(x * a - c)/ b
// 100 = 95 + 5
// x * 100 = y * 95 + 5
// 5 * 100 = y * 95 + 5
// 500 = y * 95 + 5
// 495 = y * 95
// y = 495 / 95

188
primitives.scad Normal file
View file

@ -0,0 +1,188 @@
include <globals.scad>
id = function (x) x;
lerp = function (v, old_min, old_max, new_min, new_max) (v-old_min)/(old_max-old_min)*(new_max-new_min)+new_min;
scalc = function (f, v, min, max) lerp(f(lerp(v, min, max, 0, 1)), 0, 1, min, max);
normalize = function (vector) vector / norm(vector);
mat_T = function (mat) [
for (x_y=[0:len(mat[0])-1]) [
for (y_x=[0:len(mat)-1]) mat[y_x][x_y]
]
];
rotation_matrix = function(a) [
[cos(a), -sin(a), 0],
[sin(a), cos(a), 0],
[ 0, 0, 1]
];
bezier_matrix = [[1, -3, 3, -1],
[0, 3, -6, 3],
[0, 0, 3, -3],
[0, 0, 0, 1]];
spline = function (control_points, spline_matrix, t) mat_T(control_points) * spline_matrix * [1, t, t*t, t*t*t];
bezier_spline = function (control_points, t) spline(control_points, bezier_matrix, t);
bezier_curve_vertices = function (control_points, $fn=$fn) [
for (t=[0:1/($fn-1):1]) bezier_spline(control_points, t)
];
module bezier_curve_debug(control_points, $fn=$fn) {
#color("red") for (c = control_points) translate(c) sphere(d=4, $fn=32);
color("yellow") for (v = bezier_curve_vertices(control_points, $fn)) translate(v) sphere(d=.5, $fn=16);
color("green") translate(bezier_spline(control_points, 0.5)) sphere(d=1, $fn=24);
}
// c^2=a^2+b^2 // a == b
// c^2=2a^2 // /2
// c^2/2=a^2 // sqrt
// sqrt(c^2/2)=a
//chamfer_offset = function (c) sqrt((c*c)/2);
chamfer_offset = function (c) c/2;
rendered_curve_segment_vertices = function (p, v, n, width, height, chamfer)
let (d=normalize(n-p)) let (up=[0, 0, 1]) let (right=normalize(cross(d, up))) [
//p, v, n, width, height, chamfer_offset(chamfer), d, up, right,
v+up*(height/2)+right*(-width/2+chamfer_offset(chamfer)),
v+up*(height/2)+right*(width/2-chamfer_offset(chamfer)),
v+up*(height/2-chamfer_offset(chamfer))+right*(width/2),
v+up*(-height/2+chamfer_offset(chamfer))+right*(width/2),
v+up*(-height/2)+right*(width/2-chamfer_offset(chamfer)),
v+up*(-height/2)+right*(-width/2+chamfer_offset(chamfer)),
v+up*(-height/2+chamfer_offset(chamfer))+right*(-width/2),
v+up*(height/2-chamfer_offset(chamfer))+right*(-width/2)
];
module render_curve(curve_vertices, width, height, chamfer, debug=false) {
/*
* vertex generation order:
* - we generate vertices segment by segment
* - one segement for every curve vertex provided
* - each segment has eight vertices that form the outer ring
* - the corners are chamfered so the vertices are pairs at the corners
* - we start with the top segment and move clockwise
* - top-down axis is determined globally by z-axis unless direction at start vertex is z
* - if direction at start vertes is z, top-down is y-adis instead
* - the left vertex of the top edge is 0, the other is 1
* - left-right axis is determined by normal between travel direction and up-down axis
* - the last vertex is part of the same corner as 0 but part of the left edge
* - segment edge n has vertices `n` and `(n+1)%8`
* - segment joining edge n has vertices local index `n` of both segments
* - global `i` index of local index `n` for segment `m` is `i=8*m+n`
* - so we have `count=length(curve_vertices)` segments and `count*8` vertices
* - we are not generating a thorus so the faces for our polyhedron are:
* - two eight sided end cap faces
* - `(count-1)*8` four sided mantle faces
* - direction at vertex is the vector from the previonus to the next vertex
* - for the first an last vertex the only neighbor is mirrored around the vertex
* - the start end cap is face `0`
* - the face mantle face n has vertices `[n, +(n+1)%8, n+8, n+8+(n+1)%8]`
* - the stop end cap is face `count*8`
*/
start = let(v=curve_vertices[0], n=curve_vertices[1]) let(p=v+(v-n))
rendered_curve_segment_vertices(p, v, n, width, height, chamfer);
echo("len(curve_vertices): ", len(curve_vertices));
middle = [ for (i=[1:len(curve_vertices)-2]) let(
p = curve_vertices[i-1],
v = curve_vertices[i],
n = curve_vertices[i+1]
) each rendered_curve_segment_vertices(p, v, n, width, height, chamfer)
];
echo("len(middle): ", len(middle));
stop = let(i=len(curve_vertices))
let(v=curve_vertices[i-1], p=curve_vertices[i-2]) let(n=v+(v-p))
rendered_curve_segment_vertices(p, v, n, width, height, chamfer);
if (debug) {
echo(start);
color("#ff00ff") for (v = start) translate(v+[0, 0, height]) sphere(d=.25, $fn=16);
echo(middle);
color("white") for (v = middle) translate(v+[0, 0, height]) sphere(d=.25, $fn=16);
echo(stop);
color("cyan") for (v = stop) translate(v+[0, 0, height]) sphere(d=.25, $fn=16);
}
render_vertices = concat(start, middle, stop);
echo("len(render_vertices)", len(render_vertices));
echo(render_vertices);
start_cap = [ for (i=[0:1:7]) i];
echo(start_cap);
mantle = let (M=len(curve_vertices)-1) [ for (m=[0:M-1],n=[0:7]) let (i=m*8+n)
[i, i+8, n==7 ? i+1 : i+8+1, n==7 ? i-7 : i+1]
];
echo(mantle);
end_cap = let (m=len(curve_vertices)-1) [ for (i=[m*8+7:-1:m*8]) i ];
echo(end_cap);
faces = concat([start_cap], mantle, [end_cap]);
translate([0, 0, debug ? height : 0]) polyhedron(points=render_vertices, faces=faces);
}
arc_vertex = function (a, r, t, translate=[0,0,0], remap=id) remap([
translate.x+cos(a*t)*r,
translate.y+sin(a*t)*r,
translate.z
]);
arc_vertices = function (a, r, t, x=0, y=0, z=0, remap=id, arc_vertex=arc_vertex) [
for (i=[0:1/(t-1):1]) arc_vertex(a, r, i, translate=[x,y,z], remap=remap)
];
module arc(part, radius, thickness, height, $fn=$fn, outer_remap=id, inner_remap=id, arc_vertices=arc_vertices) {
a = 360 * part;
r = radius+thickness/2;
w = thickness;
h = height;
t = $fn;
vertices_lower_outer = arc_vertices(a, r , t, z=-h/2, remap=outer_remap);
vertices_lower_inner = arc_vertices(a, r-w, t, z=-h/2, remap=inner_remap);
vertices_upper_outer = arc_vertices(a, r , t, z= h/2, remap=outer_remap);
vertices_upper_inner = arc_vertices(a, r-w, t, z= h/2, remap=inner_remap);
vertices = concat(
vertices_lower_outer,
vertices_lower_inner,
vertices_upper_outer,
vertices_upper_inner
);
faces_end1 = [ 0, t, 3*t, 2*t];
faces_end2 = [ 2*t-1, t-1, 3*t-1, 4*t-1];
faces_lower = concat(
[ for (i=[t-1:-1:0]) i ],
[ for (i=[t:1:2*t-1]) i ]
);
faces_upper = concat(
[ for (i=[2*t:1:3*t-1]) i ],
[ for (i=[4*t-1:-1:3*t]) i ]
);
faces_outer = [ for (i=[0:1:t-2]) [i, 2*t+i, 2*t+i+1, i+1] ];
faces_inner = [ for (i=[0:1:t-2]) [t+i, t+i+1, 3*t+i+1, 3*t+i] ];
faces = concat(
[faces_end1],
[faces_end2],
[faces_lower],
[faces_upper],
faces_outer,
faces_inner
);
rotate(a/2) polyhedron(vertices, faces);
}
module partial_ring(part, radius, thickness, height) {
rotate(180-180*part, [0, 0, 1])
rotate_extrude(angle=360*part)
translate([radius, 0])
square([thickness, height], center=true);
}