OpenSCAD-Generators/decorative-insects/decorative-insects.scad

1051 lines
No EOL
38 KiB
OpenSCAD

/*
PARAMETRISK DEKORATIV INSEKT-GENERATOR v3
-----------------------------------------
For OpenSCAD (gerne Nightly, men uden eksterne biblioteker).
Formaal:
- 3D-print (STL / 3MF)
- laserskaering (SVG / DXF)
- folieskaering / vinyl
- gravering / relief
Nyheder i v3:
- Flere arts-/morfologi-presets inkl. Admiral, Paafugleoje, Blue_Morpho,
Kejserguldsmed og vandnymfe-varianter.
- Stencil/bridge-mode til laser og folie, saa indre oeer kan forbindes.
- Multi-layer output for separate krop/vinger/dekoration/pletter.
- Panel-/grid-generator til batch-produktion.
- Ornamental / Art Nouveau mode med ekstra dekorative kurver.
- Fortsat produktionsprofiler og robust 2D/3D-output.
*/
// ============================== //
// [00 - Art / output] //
// ============================== //
Artspreset = "Fri"; // [Fri,Monark,Admiral,Paafugleoje,Morpho,Blue_Morpho,Svalehale,Luna,Atlas,Guldsmed_Stor,Kejserguldsmed,Vandnymfe,Vandnymfe_Smal,Cikade,Mariehoene,Skarabee]
Bruger_Type = "Sommerfugl"; // [Sommerfugl,Natsvaermer,Guldsmed,Cikade,Bille,Fantasi]
Output = "3D_RELIEF"; // [2D_SILHOUET,2D_DEKORATION,2D_COMBINED,3D_FLAT,3D_RELIEF]
// Samlet vingefang. For guldsmed/cikade er det bredeste vingesaet.
Vingefang = 100; // [20:1:320]
// Samlet laengde fra hale til antennespids, omtrentligt.
Kropslaengde = 52; // [10:1:220]
// Global skalering i laengderetningen; 1.0 = naturligt preset-forhold.
Laengde_Skala = 1.00; // [0.50:0.01:2.20]
// ============================== //
// [01 - Produktionsprofil] //
// ============================== //
Produktionsprofil = "Brugerdefineret"; // [Brugerdefineret,3D_Print_Robust,Laser_Fin,Folie_Simpel,Gravering_Relief]
Automatisk_Produktionsoptimering = true;
// ============================== //
// [02 - Symmetri / stil] //
// ============================== //
// 0 = fuldstaendig spejlsymmetrisk. Smaa vaerdier giver organisk variation.
Asymmetri = 0.00; // [0.00:0.01:0.15]
// Giver blodere former med offset-runding.
Bloedgoering = 0.35; // [0:0.05:2]
// Minimum bredde paa tynde dekorative elementer.
Min_Feature = 0.80; // [0.20:0.05:5]
// Polygon-/kurveoploesning. Hoejere er glattere men langsommere.
Oploesning = 56; // [16:4:180]
// ============================== //
// [03 - Vinger generelt] //
// ============================== //
Vinge_Laengde = 1.00; // [0.60:0.01:1.60]
Vinge_Bredde = 1.00; // [0.50:0.01:1.80]
// Flytter vingespids frem (+) eller tilbage (-).
Vinge_Sweep = 0.00; // [-0.50:0.01:0.50]
// 0 = buttet/oval, 1 = spids.
Vingespids = 0.45; // [0.00:0.01:1.00]
// 0 = jaevn bredde, 1 = kraftigt smallere mod spidsen.
Vinge_Taper = 0.35; // [0.00:0.01:0.90]
// Rotation af hele vingeparret.
Vinge_Vinkel = 0; // [-35:1:35]
// Indtraek mellem krop og vingens geometriske start.
Vinge_Rod_Overlap = 1.5; // [0:0.25:10]
// Indhak i forvingens bagkant naer roden.
Forvinge_Indhak = 0.00; // [0.00:0.01:1.00]
// Bagvingens boelgede/scalloped bagkant.
Bagvinge_Skalop = 0.00; // [0.00:0.01:1.00]
// ============================== //
// [04 - Sommerfugl / natsvaermer]//
// ============================== //
Forvinge_Skala = 1.00; // [0.60:0.01:1.60]
Bagvinge_Skala = 0.88; // [0.50:0.01:1.60]
Bagvinge_Forskydning = -7; // [-30:0.5:20]
Bagvinge_Runding = 0.65; // [0.00:0.01:1.00]
// 0 = ingen hale; hoejere = svalehale-/luna-lignende hale.
Vinge_Hale = 0.00; // [0.00:0.01:1.00]
// ============================== //
// [05 - Guldsmed / cikade] //
// ============================== //
Langvinge_For_Skala = 1.00; // [0.60:0.01:1.30]
Langvinge_Bag_Skala = 0.92; // [0.60:0.01:1.30]
Langvinge_Separation = 8.0; // [2:0.5:30]
Langvinge_Rod_Bredde = 0.42; // [0.15:0.01:0.85]
Langvinge_Spids_Bredde = 0.55; // [0.15:0.01:1.00]
// Lille farvet / graferbar pterostigma-lignende markering naer spidsen.
Pterostigma = true;
Pterostigma_Skala = 1.00; // [0.40:0.05:2.50]
// ============================== //
// [06 - Krop] //
// ============================== //
Krop_Bredde = 7.0; // [1:0.25:30]
Bryst_Skala = 1.15; // [0.60:0.01:2.00]
Hoved_Skala = 0.90; // [0.50:0.01:2.00]
Bagkrop_Taper = 0.55; // [0.10:0.01:1.00]
Bagkrop_Segmenter = 6; // [0:1:18]
Talje = 0.15; // [0.00:0.01:0.80]
// ============================== //
// [07 - Antenner / ben] //
// ============================== //
Antenner = true;
Antenne_Laengde = 12; // [0:0.5:50]
Antenne_Spredning = 28; // [0:1:80]
Antenne_Krumning = 0.35; // [-1.00:0.05:1.00]
Antenne_Knop = 0.0; // [0:0.1:4]
// Simpel pseudo-fjering paa antenner, nyttig til natsvaermere.
Antenne_Fjering = 0.00; // [0.00:0.05:2.00]
Ben = false;
Ben_Laengde = 10; // [2:0.5:30]
Ben_Vinkel = 35; // [5:1:80]
// ============================== //
// [08 - Vingedekoration / aarer] //
// ============================== //
Vinge_Aarer = true;
Aare_Tykkelse = 0.65; // [0.20:0.05:3]
Aare_Taethed = 5; // [1:1:14]
Tvaer_Aarer = true;
Aare_Organisk = 0.55; // [0.00:0.01:1.00]
Vinge_Pletter = true;
Plet_Antal = 2; // [0:1:6]
Plet_Skala = 1.0; // [0.3:0.05:3]
Plet_Ring = true;
// Elytra-/dækningsdekor til biller / mariehoener.
Daekvinge_Soem = true;
Daekvinge_Pletter = true;
Daekvinge_Plet_Antal = 3; // [0:1:8]
// ============================== //
// [09 - Kant / udskaeringer] //
// ============================== //
Ydre_Kant = 0.0; // [0:0.1:5]
Udskaering = 0.0; // [0.00:0.05:1.00]
Udskaering_Margin = 3.0; // [0.5:0.25:10]
// ============================== //
// [10 - Ophaeng / montage] //
// ============================== //
Ophaengshul = false;
Ophaengshul_Diameter = 3.2; // [1:0.1:10]
Ophaengshul_Y = 0; // [-20:0.5:20]
// ============================== //
// [11 - 3D] //
// ============================== //
Tykkelse = 2.4; // [0.4:0.1:12]
Relief_Hoejde = 0.70; // [0.1:0.05:5]
Relief_Haevede_Detaljer = true;
// ============================== //
// [12 - Stencil / bridges] //
// ============================== //
Stencil_Mode = false;
// Brobredde til at forbinde indre oeer med yderkonturen.
Stencil_Bro_Bredde = 1.20; // [0.30:0.05:6]
// Antal broer pr. side, placeret radialt mod vingerne.
Stencil_Bro_Antal = 2; // [1:1:6]
// Hvor langt broer ma gaa ind i silhuetten.
Stencil_Bro_Laengde = 18; // [4:0.5:50]
// Tilfoej bro til ophaengshul / centrale huller.
Stencil_Centerbro = true;
// ============================== //
// [13 - Multi-layer output] //
// ============================== //
Layer_Output = "Alle"; // [Alle,Vinger,Krop,Aarer,Pletter,Stencilbroer]
// Lidt overlap mellem separate lag kan vaere nyttigt til vinyl/laserregistrering.
Layer_Overlap = 0.20; // [0:0.05:2]
// ============================== //
// [14 - Panel / batch] //
// ============================== //
Panel_Mode = false;
Panel_Kolonner = 3; // [1:1:10]
Panel_Raekker = 2; // [1:1:10]
Panel_Afstand_X = 125; // [20:1:400]
Panel_Afstand_Y = 95; // [20:1:400]
Panel_Skiftevis_Spejling = false;
Panel_Skiftevis_Rotation = 0; // [-180:5:180]
// ============================== //
// [15 - Ornamental / Art Nouveau]//
// ============================== //
Ornamental_Mode = false;
Ornamental_Styrke = 0.55; // [0.00:0.05:1.50]
Ornamental_Tykkelse = 0.70; // [0.20:0.05:4]
Ornamental_Slyng = 3; // [1:1:8]
Ornamental_Ringe = true;
// ============================== //
// [16 - Preview] //
// ============================== //
Vis_Centerlinje = false;
$fn = Oploesning;
EPS = 0.01;
// ------------------------------------------------------------
// Hjaelpefunktioner
// ------------------------------------------------------------
function clamp(v,a,b) = min(max(v,a),b);
function lerp(a,b,t) = a + (b-a)*t;
function v2lerp(a,b,t) = [lerp(a[0],b[0],t), lerp(a[1],b[1],t)];
function bz3(p0,p1,p2,p3,t) =
let(u=1-t)
[u*u*u*p0[0] + 3*u*u*t*p1[0] + 3*u*t*t*p2[0] + t*t*t*p3[0],
u*u*u*p0[1] + 3*u*u*t*p1[1] + 3*u*t*t*p2[1] + t*t*t*p3[1]];
function bez3pts(p0,p1,p2,p3,n=16) = [for(i=[0:n]) bz3(p0,p1,p2,p3,i/n)];
function profile_min_floor() =
Produktionsprofil=="3D_Print_Robust" ? 0.80 :
Produktionsprofil=="Laser_Fin" ? 0.35 :
Produktionsprofil=="Folie_Simpel" ? 0.60 :
Produktionsprofil=="Gravering_Relief" ? 0.45 : 0;
function eff_min_feature() = max(Min_Feature, Automatisk_Produktionsoptimering ? profile_min_floor() : 0);
function eff_vein_thickness() = max(Aare_Tykkelse, eff_min_feature()*0.60);
function eff_outline() = Ydre_Kant + (Automatisk_Produktionsoptimering && Produktionsprofil=="3D_Print_Robust" ? eff_min_feature()*0.20 : 0);
function eff_cutout() = Automatisk_Produktionsoptimering && (Produktionsprofil=="3D_Print_Robust" || Produktionsprofil=="Folie_Simpel") ? min(Udskaering,0.35) : Udskaering;
function eff_veins_enabled() = Automatisk_Produktionsoptimering && Produktionsprofil=="Folie_Simpel" ? false : Vinge_Aarer;
function eff_spots_enabled() = Automatisk_Produktionsoptimering && Produktionsprofil=="Folie_Simpel" ? false : Vinge_Pletter;
function eff_crossveins() = Automatisk_Produktionsoptimering && Produktionsprofil=="Folie_Simpel" ? false : Tvaer_Aarer;
function eff_deck_spots() = Automatisk_Produktionsoptimering && Produktionsprofil=="Folie_Simpel" ? false : Daekvinge_Pletter;
function chosen_family() =
Artspreset=="Fri" ? Bruger_Type :
Artspreset=="Monark" ? "Sommerfugl" :
Artspreset=="Admiral" ? "Sommerfugl" :
Artspreset=="Paafugleoje" ? "Sommerfugl" :
Artspreset=="Morpho" ? "Sommerfugl" :
Artspreset=="Blue_Morpho" ? "Sommerfugl" :
Artspreset=="Svalehale" ? "Sommerfugl" :
Artspreset=="Luna" ? "Natsvaermer" :
Artspreset=="Atlas" ? "Natsvaermer" :
Artspreset=="Guldsmed_Stor" ? "Guldsmed" :
Artspreset=="Kejserguldsmed" ? "Guldsmed" :
Artspreset=="Vandnymfe" ? "Guldsmed" :
Artspreset=="Vandnymfe_Smal" ? "Guldsmed" :
Artspreset=="Cikade" ? "Cikade" :
Artspreset=="Mariehoene" ? "Bille" :
Artspreset=="Skarabee" ? "Bille" : Bruger_Type;
function is_butterfly() = chosen_family()=="Sommerfugl" || chosen_family()=="Natsvaermer" || chosen_family()=="Fantasi";
function is_longwing() = chosen_family()=="Guldsmed" || chosen_family()=="Cikade";
function is_beetle() = chosen_family()=="Bille";
function art_adj_forwing() =
Artspreset=="Monark" ? 1.00 :
Artspreset=="Admiral" ? 0.98 :
Artspreset=="Paafugleoje" ? 1.03 :
Artspreset=="Morpho" ? 1.08 :
Artspreset=="Blue_Morpho" ? 1.10 :
Artspreset=="Svalehale" ? 1.02 :
Artspreset=="Luna" ? 0.98 :
Artspreset=="Atlas" ? 1.12 :
1.00;
function art_adj_hindwing() =
Artspreset=="Monark" ? 0.92 :
Artspreset=="Admiral" ? 0.88 :
Artspreset=="Paafugleoje" ? 0.96 :
Artspreset=="Morpho" ? 1.00 :
Artspreset=="Blue_Morpho" ? 1.02 :
Artspreset=="Svalehale" ? 0.82 :
Artspreset=="Luna" ? 0.96 :
Artspreset=="Atlas" ? 1.05 :
0.88;
function art_adj_rounding() =
Artspreset=="Morpho" ? 0.82 :
Artspreset=="Blue_Morpho" ? 0.86 :
Artspreset=="Paafugleoje" ? 0.78 :
Artspreset=="Admiral" ? 0.60 :
Artspreset=="Monark" ? 0.62 :
Artspreset=="Svalehale" ? 0.54 :
Artspreset=="Luna" ? 0.86 :
Artspreset=="Atlas" ? 0.76 :
Bagvinge_Runding;
function art_adj_tail() =
Artspreset=="Svalehale" ? 0.52 :
Artspreset=="Luna" ? 0.86 :
Artspreset=="Atlas" ? 0.18 :
Vinge_Hale;
function art_adj_tip() =
Artspreset=="Monark" ? 0.46 :
Artspreset=="Admiral" ? 0.55 :
Artspreset=="Paafugleoje" ? 0.40 :
Artspreset=="Morpho" ? 0.30 :
Artspreset=="Blue_Morpho" ? 0.26 :
Artspreset=="Svalehale" ? 0.64 :
Artspreset=="Luna" ? 0.42 :
Artspreset=="Atlas" ? 0.38 :
Vingespids;
function art_adj_taper() =
Artspreset=="Monark" ? 0.36 :
Artspreset=="Admiral" ? 0.42 :
Artspreset=="Paafugleoje" ? 0.30 :
Artspreset=="Morpho" ? 0.22 :
Artspreset=="Blue_Morpho" ? 0.18 :
Artspreset=="Svalehale" ? 0.48 :
Artspreset=="Luna" ? 0.30 :
Artspreset=="Atlas" ? 0.24 :
Vinge_Taper;
function art_adj_sweep() =
Artspreset=="Monark" ? 0.04 :
Artspreset=="Morpho" ? 0.00 :
Artspreset=="Svalehale" ? 0.06 :
Artspreset=="Luna" ? -0.08 :
Artspreset=="Atlas" ? -0.04 :
Artspreset=="Guldsmed_Stor" ? 0.02 :
Artspreset=="Kejserguldsmed" ? 0.05 :
Artspreset=="Vandnymfe" ? -0.06 :
Artspreset=="Vandnymfe_Smal" ? -0.10 :
Artspreset=="Cikade" ? 0.00 :
Vinge_Sweep;
function art_adj_fore_notch() =
Artspreset=="Svalehale" ? 0.42 :
Artspreset=="Atlas" ? 0.25 :
Forvinge_Indhak;
function art_adj_scallop() =
Artspreset=="Morpho" ? 0.12 :
Artspreset=="Svalehale" ? 0.34 :
Artspreset=="Luna" ? 0.20 :
Bagvinge_Skalop;
function art_adj_long_sep() =
Artspreset=="Guldsmed_Stor" ? 11 :
Artspreset=="Kejserguldsmed" ? 12 :
Artspreset=="Vandnymfe" ? 7 :
Artspreset=="Vandnymfe_Smal" ? 5.5 :
Artspreset=="Cikade" ? 8 :
Langvinge_Separation;
function art_adj_root_width() =
Artspreset=="Guldsmed_Stor" ? 0.34 :
Artspreset=="Kejserguldsmed" ? 0.38 :
Artspreset=="Vandnymfe" ? 0.26 :
Artspreset=="Vandnymfe_Smal" ? 0.20 :
Artspreset=="Cikade" ? 0.48 :
Langvinge_Rod_Bredde;
function art_adj_tip_width() =
Artspreset=="Guldsmed_Stor" ? 0.46 :
Artspreset=="Kejserguldsmed" ? 0.50 :
Artspreset=="Vandnymfe" ? 0.34 :
Artspreset=="Vandnymfe_Smal" ? 0.28 :
Artspreset=="Cikade" ? 0.66 :
Langvinge_Spids_Bredde;
function art_adj_thorax() =
Artspreset=="Guldsmed_Stor" ? 1.25 :
Artspreset=="Vandnymfe" ? 1.05 :
Artspreset=="Cikade" ? 1.15 :
Artspreset=="Mariehoene" ? 1.35 :
Artspreset=="Skarabee" ? 1.22 :
Bryst_Skala;
function art_adj_head() =
Artspreset=="Guldsmed_Stor" ? 1.18 :
Artspreset=="Vandnymfe" ? 1.06 :
Artspreset=="Cikade" ? 1.20 :
Artspreset=="Mariehoene" ? 0.88 :
Artspreset=="Skarabee" ? 0.92 :
Hoved_Skala;
function art_adj_ab_taper() =
Artspreset=="Guldsmed_Stor" ? 0.38 :
Artspreset=="Vandnymfe" ? 0.32 :
Artspreset=="Cikade" ? 0.72 :
Artspreset=="Mariehoene" ? 0.90 :
Artspreset=="Skarabee" ? 0.74 :
Bagkrop_Taper;
function art_adj_segments() =
Artspreset=="Guldsmed_Stor" ? 9 :
Artspreset=="Vandnymfe" ? 8 :
Artspreset=="Cikade" ? 7 :
Artspreset=="Mariehoene" ? 4 :
Artspreset=="Skarabee" ? 5 :
Bagkrop_Segmenter;
function art_body_w_factor() =
Artspreset=="Mariehoene" ? 1.55 :
Artspreset=="Skarabee" ? 1.35 :
Artspreset=="Guldsmed_Stor" ? 0.72 :
Artspreset=="Vandnymfe" ? 0.58 :
Artspreset=="Cikade" ? 1.22 :
1.00;
function art_body_len_factor() =
Artspreset=="Guldsmed_Stor" ? 1.22 :
Artspreset=="Vandnymfe" ? 1.14 :
Artspreset=="Mariehoene" ? 0.70 :
Artspreset=="Skarabee" ? 0.82 :
1.00;
function art_ant_len() =
Artspreset=="Luna" ? 16 :
Artspreset=="Atlas" ? 15 :
Artspreset=="Guldsmed_Stor" ? 5 :
Artspreset=="Vandnymfe" ? 5 :
Artspreset=="Cikade" ? 6 :
Antenne_Laengde;
function art_ant_spread() =
Artspreset=="Luna" ? 34 :
Artspreset=="Atlas" ? 28 :
Artspreset=="Guldsmed_Stor" ? 18 :
Artspreset=="Vandnymfe" ? 14 :
Artspreset=="Cikade" ? 18 :
Antenne_Spredning;
function art_ant_fan() =
Artspreset=="Luna" ? 1.25 :
Artspreset=="Atlas" ? 1.00 :
Antenne_Fjering;
function art_vein_density() =
Artspreset=="Monark" ? 6 :
Artspreset=="Admiral" ? 5 :
Artspreset=="Paafugleoje" ? 5 :
Artspreset=="Morpho" ? 5 :
Artspreset=="Blue_Morpho" ? 5 :
Artspreset=="Svalehale" ? 5 :
Artspreset=="Luna" ? 4 :
Artspreset=="Atlas" ? 4 :
Artspreset=="Guldsmed_Stor" ? 7 :
Artspreset=="Kejserguldsmed" ? 8 :
Artspreset=="Vandnymfe" ? 6 :
Artspreset=="Vandnymfe_Smal" ? 6 :
Artspreset=="Cikade" ? 8 :
Aare_Taethed;
function art_spot_count() =
Artspreset=="Monark" ? 1 :
Artspreset=="Admiral" ? 2 :
Artspreset=="Paafugleoje" ? 3 :
Artspreset=="Morpho" ? 0 :
Artspreset=="Blue_Morpho" ? 0 :
Artspreset=="Svalehale" ? 2 :
Artspreset=="Luna" ? 2 :
Artspreset=="Atlas" ? 1 :
Plet_Antal;
function art_spots_default() =
Artspreset=="Morpho" ? false :
Artspreset=="Blue_Morpho" ? false :
Artspreset=="Guldsmed_Stor" ? false :
Artspreset=="Kejserguldsmed" ? false :
Artspreset=="Vandnymfe_Smal" ? false :
Artspreset=="Vandnymfe" ? false :
Artspreset=="Cikade" ? false :
is_butterfly();
function eff_body_w() = Krop_Bredde * art_body_w_factor() * (chosen_family()=="Guldsmed" ? 0.65 : chosen_family()=="Cikade" ? 1.15 : chosen_family()=="Bille" ? 1.35 : 1);
function eff_body_len() = Kropslaengde * Laengde_Skala * art_body_len_factor() * (chosen_family()=="Guldsmed" ? 1.15 : chosen_family()=="Bille" ? 0.80 : 1);
function eff_forwing_scale() = Forvinge_Skala * art_adj_forwing();
function eff_hindwing_scale() = Bagvinge_Skala * art_adj_hindwing();
function eff_hindwing_round() = clamp(Artspreset=="Fri" ? Bagvinge_Runding : art_adj_rounding(),0,1);
function eff_wing_tail() = clamp(Artspreset=="Fri" ? Vinge_Hale : art_adj_tail(),0,1);
function eff_tip() = clamp(Artspreset=="Fri" ? Vingespids : art_adj_tip(),0,1);
function eff_taper() = clamp(Artspreset=="Fri" ? Vinge_Taper : art_adj_taper(),0,0.95);
function eff_sweep() = Artspreset=="Fri" ? Vinge_Sweep : art_adj_sweep();
function eff_notch() = clamp(Artspreset=="Fri" ? Forvinge_Indhak : art_adj_fore_notch(),0,1);
function eff_scallop() = clamp(Artspreset=="Fri" ? Bagvinge_Skalop : art_adj_scallop(),0,1);
function eff_long_sep() = Artspreset=="Fri" ? Langvinge_Separation : art_adj_long_sep();
function eff_long_rootw() = Artspreset=="Fri" ? Langvinge_Rod_Bredde : art_adj_root_width();
function eff_long_tipw() = Artspreset=="Fri" ? Langvinge_Spids_Bredde : art_adj_tip_width();
function eff_thorax_scale() = Artspreset=="Fri" ? Bryst_Skala : art_adj_thorax();
function eff_head_scale() = Artspreset=="Fri" ? Hoved_Skala : art_adj_head();
function eff_ab_taper() = Artspreset=="Fri" ? Bagkrop_Taper : art_adj_ab_taper();
function eff_segments() = Artspreset=="Fri" ? Bagkrop_Segmenter : art_adj_segments();
function eff_ant_len() = Artspreset=="Fri" ? Antenne_Laengde : art_ant_len();
function eff_ant_spread() = Artspreset=="Fri" ? Antenne_Spredning : art_ant_spread();
function eff_ant_fan() = Artspreset=="Fri" ? Antenne_Fjering : art_ant_fan();
function eff_vein_density_count() = Artspreset=="Fri" ? Aare_Taethed : art_vein_density();
function eff_spot_count() = Artspreset=="Fri" ? Plet_Antal : art_spot_count();
function eff_spot_state() = eff_spots_enabled() && (Artspreset=="Fri" ? Vinge_Pletter : art_spots_default());
module stroke_polyline(pts, w=1) {
ww=max(w,eff_min_feature());
for(i=[0:len(pts)-2]) hull() {
translate(pts[i]) circle(d=ww);
translate(pts[i+1]) circle(d=ww);
}
}
module stroke_bezier(p0,p1,p2,p3,w=1,n=14) {
stroke_polyline(bez3pts(p0,p1,p2,p3,n),w);
}
module soft2d(r=Bloedgoering) {
if(r>0) offset(r=r) offset(delta=-r) children();
else children();
}
module mirrored_pair() {
children();
mirror([1,0,0]) children();
}
// ------------------------------------------------------------
// Vingegeometri
// ------------------------------------------------------------
module butterfly_forewing_half(scale_fac=1) {
span = Vingefang/2 * 0.96 * Vinge_Laengde * eff_forwing_scale() * scale_fac;
chord = Vingefang * 0.29 * Vinge_Bredde * scale_fac * (chosen_family()=="Natsvaermer" ? 0.78 : 1);
rootx = eff_body_w()/2 - Vinge_Rod_Overlap;
rooty = eff_body_len()*0.08;
sweep = eff_sweep() * chord;
tipy = rooty + chord*(0.45+sweep/chord);
tip_round = 1-eff_tip();
taper=eff_taper();
notch=eff_notch();
p0=[rootx, rooty-chord*0.28];
p1=[rootx+span*0.22, rooty-chord*0.48];
p2=[rootx+span*0.72, tipy-chord*(0.42-0.15*tip_round)];
p3=[rootx+span, tipy];
p4=[rootx+span*(0.82+0.10*tip_round), tipy+chord*(0.16+0.10*tip_round)];
p5=[rootx+span*(0.45+0.08*taper), rooty+chord*(0.46-0.12*taper)];
pn=[rootx+span*(0.16+0.10*notch), rooty+chord*(0.34-0.18*notch)];
p6=[rootx, rooty+chord*0.28];
rotate(Vinge_Vinkel)
soft2d()
polygon(concat(
bez3pts(p0,p1,p2,p3,10),
bez3pts(p3,p4,p4,p5,8),
bez3pts(p5,pn,pn,p6,8)
));
}
module butterfly_hindwing_half(scale_fac=1) {
span = Vingefang/2 * 0.72 * Vinge_Laengde * eff_hindwing_scale() * scale_fac;
chord = Vingefang * 0.28 * Vinge_Bredde * scale_fac;
rootx=eff_body_w()/2 - Vinge_Rod_Overlap;
rooty=-eff_body_len()*0.04 + Bagvinge_Forskydning;
round=eff_hindwing_round();
tail=eff_wing_tail();
scal=eff_scallop();
p0=[rootx,rooty+chord*0.35];
p1=[rootx+span*0.22,rooty+chord*0.46];
p2=[rootx+span*0.78,rooty+chord*0.40];
p3=[rootx+span,rooty+chord*(0.05+0.10*eff_sweep())];
p4=[rootx+span*(0.96-0.12*round),rooty-chord*(0.28+0.20*round)];
pd=[rootx+span*(0.68-0.08*scal),rooty-chord*(0.42+0.22*scal)];
tailp=[rootx+span*(0.62+0.10*tail),rooty-chord*(0.45+0.50*tail)];
p5=[rootx+span*(0.34+0.12*round),rooty-chord*(0.40+0.18*round)];
p6=[rootx,rooty-chord*0.22];
rotate(Vinge_Vinkel*0.45)
soft2d()
polygon(concat(
bez3pts(p0,p1,p2,p3,9),
tail>0.02 ? concat(bez3pts(p3,p4,p4,tailp,6), bez3pts(tailp,pd,p5,p6,8))
: concat(bez3pts(p3,p4,pd,p5,8), bez3pts(p5,p5,p6,p6,3))
));
}
module longwing_half(yshift=0, scale_fac=1, rear=false) {
span=Vingefang/2 * 0.98 * Vinge_Laengde * scale_fac;
width=Vingefang * (chosen_family()=="Cikade" ? 0.16 : 0.105) * Vinge_Bredde * (rear ? 1.06 : 1);
rootx=eff_body_w()/2 - Vinge_Rod_Overlap;
rooty=yshift;
rootw=width*eff_long_rootw();
tipw=width*eff_long_tipw();
sweep=eff_sweep()*width*1.4;
p0=[rootx,rooty-rootw/2];
p1=[rootx+span*0.28,rooty-width*0.56];
p2=[rootx+span*0.77,rooty+sweep-width*0.46];
p3=[rootx+span,rooty+sweep-tipw*0.08];
p4=[rootx+span,rooty+sweep+tipw*0.18];
p5=[rootx+span*0.70,rooty+sweep+width*0.48];
p6=[rootx+span*0.22,rooty+width*0.48];
p7=[rootx,rooty+rootw/2];
rotate(Vinge_Vinkel)
soft2d()
polygon(concat(bez3pts(p0,p1,p2,p3,10),bez3pts(p3,p4,p5,p6,8),bez3pts(p6,p6,p7,p7,3)));
}
module beetle_elytron_half() {
span=Vingefang/2*(Artspreset=="Mariehoene" ? 0.46 : 0.53)*Vinge_Bredde;
len=eff_body_len()*(Artspreset=="Mariehoene" ? 0.56 : 0.62);
rootx=eff_body_w()*0.10;
y0=-eff_body_len()*0.12;
soft2d()
polygon(concat(
bez3pts([rootx,y0+len*0.48],[span*0.65,y0+len*0.55],[span,y0+len*0.20],[span,y0-len*0.08],10),
bez3pts([span,y0-len*0.08],[span*0.95,y0-len*0.48],[span*0.42,y0-len*0.58],[rootx,y0-len*0.52],10)
));
}
module wings_2d() {
if(is_butterfly()) {
mirrored_pair() {
butterfly_forewing_half(1 + Asymmetri);
butterfly_hindwing_half(1 + Asymmetri*0.5);
}
}
else if(is_longwing()) {
sep=eff_long_sep();
mirrored_pair() {
longwing_half(+sep/2, Langvinge_For_Skala*(1+Asymmetri), false);
longwing_half(-sep/2, Langvinge_Bag_Skala*(1+Asymmetri*0.5), true);
}
}
else if(is_beetle()) {
mirrored_pair() beetle_elytron_half();
mirrored_pair() rotate(-8) scale([1.12,0.72]) longwing_half(-3,0.72,false);
}
}
// ------------------------------------------------------------
// Krop, hoved, antenner, ben
// ------------------------------------------------------------
module body_core_2d() {
L=eff_body_len();
W=eff_body_w();
head_y=L*0.32;
thor_y=L*0.12;
abdomen_y=-L*0.13;
abdomen_len=L*0.53;
union() {
hull() {
translate([0,abdomen_y+abdomen_len*0.35]) circle(d=W*(0.82-0.28*Talje));
translate([0,abdomen_y-abdomen_len*0.48]) circle(d=W*eff_ab_taper());
}
translate([0,thor_y]) scale([eff_thorax_scale(),1.18]) circle(d=W);
hull() {
translate([0,thor_y+W*0.30]) circle(d=W*0.48);
translate([0,head_y]) scale([eff_head_scale(),0.90*eff_head_scale()]) circle(d=W);
}
}
}
module antenna_half(side=1) {
L=eff_body_len(); W=eff_body_w();
y=L*0.37;
antL=eff_ant_len();
fan=eff_ant_fan();
p0=[side*W*0.20,y];
p1=[side*(W*0.35 + antL*0.18), y+antL*0.30];
p2=[side*(W*0.35 + antL*(0.48+0.12*Antenne_Krumning)), y+antL*0.68];
p3=[side*(W*0.30 + antL*sin(eff_ant_spread())), y+antL];
stroke_bezier(p0,p1,p2,p3,eff_min_feature(),14);
if(fan>0.02)
for(t=[0.18:0.12:0.82]) {
pt=bz3(p0,p1,p2,p3,t);
dir=[side*fan*antL*(0.08+0.08*t), fan*antL*(0.01+0.01*t)];
stroke_polyline([pt, pt+[dir[0],dir[1]]], eff_min_feature()*0.65);
stroke_polyline([pt, pt+[dir[0],-dir[1]]], eff_min_feature()*0.65);
}
if(Antenne_Knop>0) translate(p3) circle(d=max(Antenne_Knop,eff_min_feature()));
}
module legs_2d() {
if(Ben) {
L=eff_body_len(); W=eff_body_w();
for(yy=[-0.03,0.10,0.20])
for(s=[-1,1]) {
root=[s*W*0.30,L*yy];
knee=[s*(W*0.65+Ben_Laengde*0.38),L*yy-Ben_Laengde*0.12];
tip=[s*(W*0.65+Ben_Laengde*cos(Ben_Vinkel)),L*yy-Ben_Laengde*sin(Ben_Vinkel)];
stroke_polyline([root,knee,tip],eff_min_feature());
}
}
}
module body_2d() {
union() {
soft2d(Bloedgoering*0.5) body_core_2d();
if(Antenner) { antenna_half(-1); antenna_half(1); }
legs_2d();
}
}
// ------------------------------------------------------------
// Dekoration: aarer, pletter, kropssegmenter
// ------------------------------------------------------------
module butterfly_veins_half(fore=true) {
span=Vingefang/2 * (fore ? 0.90*eff_forwing_scale() : 0.66*eff_hindwing_scale()) * Vinge_Laengde;
chord=Vingefang * (fore ? 0.24 : 0.23) * Vinge_Bredde;
root=[eff_body_w()/2, fore ? eff_body_len()*0.08 : -eff_body_len()*0.04+Bagvinge_Forskydning];
baseang=fore ? Vinge_Vinkel : Vinge_Vinkel*0.45;
rotate(baseang) {
stroke_bezier(root,
[root[0]+span*0.25,root[1]+chord*0.02],
[root[0]+span*0.58,root[1]+chord*(fore?0.15:-0.08)],
[root[0]+span*0.90,root[1]+chord*(fore?0.28:-0.12)], eff_vein_thickness(),14);
for(i=[1:eff_vein_density_count()]) {
t=i/(eff_vein_density_count()+1);
start=[root[0]+span*(0.07+0.50*t), root[1]+chord*(fore?0.04:-0.02)];
ey = fore ? lerp(-0.31,0.48,t) : lerp(-0.38,0.30,t);
end=[root[0]+span*lerp(0.50,0.95,t), root[1]+chord*ey];
bend=Aare_Organisk*chord*0.10*sin(i*37);
stroke_bezier(start,
v2lerp(start,end,0.35)+[0,bend],
v2lerp(start,end,0.72)+[0,-bend*0.4],end,
eff_vein_thickness(),9);
}
if(eff_crossveins())
for(i=[1:max(1,eff_vein_density_count()-1)]) {
t=i/eff_vein_density_count();
x=root[0]+span*(0.34+0.45*t);
stroke_bezier([x,root[1]-chord*0.18],[x+span*0.03,root[1]-chord*0.05],
[x-span*0.02,root[1]+chord*0.15],[x,root[1]+chord*0.30],
eff_vein_thickness()*0.75,7);
}
}
}
module longwing_veins_half(yshift=0,scale_fac=1) {
span=Vingefang/2*0.91*Vinge_Laengde*scale_fac;
width=Vingefang*(chosen_family()=="Cikade"?0.14:0.09)*Vinge_Bredde;
root=[eff_body_w()/2,yshift];
rotate(Vinge_Vinkel) {
for(j=[-1,0,1])
stroke_bezier(root,
[root[0]+span*0.28,root[1]+j*width*0.22],
[root[0]+span*0.66,root[1]+j*width*0.26],
[root[0]+span*0.92,root[1]+j*width*0.16],eff_vein_thickness(),12);
if(eff_crossveins())
for(i=[1:eff_vein_density_count()]) {
t=i/(eff_vein_density_count()+1);
x=root[0]+span*(0.15+0.70*t);
w=width*(0.35+0.55*sin(t*180));
stroke_bezier([x,root[1]-w],[x+span*0.025,root[1]-w*0.3],
[x-span*0.015,root[1]+w*0.3],[x,root[1]+w],eff_vein_thickness()*0.70,6);
}
}
}
module pterostigma_half(yshift=0,scale_fac=1) {
if(Pterostigma && (chosen_family()=="Guldsmed" || chosen_family()=="Cikade")) {
span=Vingefang/2*0.91*Vinge_Laengde*scale_fac;
width=Vingefang*(chosen_family()=="Cikade"?0.14:0.09)*Vinge_Bredde;
root=[eff_body_w()/2,yshift];
rotate(Vinge_Vinkel)
translate([root[0]+span*0.82,root[1]+width*0.18])
scale([1.8,0.75]) circle(d=max(width*0.22*Pterostigma_Skala, eff_min_feature()*1.4));
}
}
module wing_spots_half() {
if(eff_spot_state() && eff_spot_count()>0 && is_butterfly()) {
span=Vingefang/2*0.90*Vinge_Laengde*eff_forwing_scale();
chord=Vingefang*0.24*Vinge_Bredde;
root=[eff_body_w()/2,eff_body_len()*0.08];
rotate(Vinge_Vinkel)
for(i=[0:eff_spot_count()-1]) {
t=(i+1)/(eff_spot_count()+1);
c=[root[0]+span*lerp(0.52,0.78,t),root[1]+chord*lerp(-0.08,0.25,t)];
d=Vingefang*0.045*Plet_Skala*(1-0.15*i);
if(Plet_Ring) {
difference() {
translate(c) circle(d=d);
translate(c) circle(d=max(d-2*max(eff_vein_thickness(),eff_min_feature()),eff_min_feature()));
}
} else translate(c) circle(d=d);
}
}
}
module beetle_spots_half() {
if(eff_deck_spots() && is_beetle()) {
span=Vingefang/2*(Artspreset=="Mariehoene" ? 0.42 : 0.45);
y0=-eff_body_len()*0.12;
for(i=[0:Daekvinge_Plet_Antal-1]) {
t=(i+1)/(Daekvinge_Plet_Antal+1);
px=eff_body_w()*0.18 + span*lerp(0.22,0.82,t);
py=y0 + eff_body_len()*lerp(0.10,-0.28,t) + (i%2==0 ? 2.0 : -1.5);
translate([px,py]) scale([1.15,0.95]) circle(d=Vingefang*0.045*(Artspreset=="Mariehoene" ? 1.0 : 0.75));
}
}
}
module body_decoration_2d() {
L=eff_body_len(); W=eff_body_w();
if(eff_segments()>0)
for(i=[0:eff_segments()-1]) {
t=(i+0.75)/(eff_segments()+1);
y=lerp(-L*0.38,L*0.05,t);
ww=lerp(W*eff_ab_taper(),W*0.75,t);
stroke_polyline([[-ww*0.34,y],[ww*0.34,y]],max(eff_vein_thickness(),eff_min_feature()));
}
stroke_polyline([[0,L*0.03],[0,L*0.22]],max(eff_vein_thickness(),eff_min_feature()));
if(Daekvinge_Soem && is_beetle())
stroke_polyline([[0,-L*0.36],[0,L*0.18]],max(eff_vein_thickness(),eff_min_feature()));
if(chosen_family()=="Cikade") {
translate([ W*0.28, L*0.30]) circle(d=max(W*0.18, eff_min_feature()));
translate([-W*0.28, L*0.30]) circle(d=max(W*0.18, eff_min_feature()));
}
}
module decorations_raw_2d() {
intersection() {
union() {
if(eff_veins_enabled()) {
if(is_butterfly()) mirrored_pair() {
butterfly_veins_half(true);
butterfly_veins_half(false);
}
else if(is_longwing()) mirrored_pair() {
longwing_veins_half(+eff_long_sep()/2,Langvinge_For_Skala);
longwing_veins_half(-eff_long_sep()/2,Langvinge_Bag_Skala);
pterostigma_half(+eff_long_sep()/2,Langvinge_For_Skala);
pterostigma_half(-eff_long_sep()/2,Langvinge_Bag_Skala);
}
else if(is_beetle()) mirrored_pair() {
stroke_bezier([eff_body_w()*0.15,eff_body_len()*0.18],
[Vingefang*0.13,eff_body_len()*0.12],
[Vingefang*0.20,-eff_body_len()*0.15],
[Vingefang*0.17,-eff_body_len()*0.35],eff_vein_thickness(),12);
}
}
wing_spots_half();
mirror([1,0,0]) wing_spots_half();
beetle_spots_half();
mirror([1,0,0]) beetle_spots_half();
}
wings_2d();
}
body_decoration_2d();
ornamental_2d();
}
// ------------------------------------------------------------
// Ornamental / Art Nouveau
// ------------------------------------------------------------
module ornamental_half() {
if(Ornamental_Mode && Ornamental_Styrke>0) {
W=Vingefang;
L=eff_body_len();
w=max(Ornamental_Tykkelse,eff_min_feature()*0.65);
for(i=[0:Ornamental_Slyng-1]) {
t=(i+1)/(Ornamental_Slyng+1);
p0=[eff_body_w()*0.40, lerp(-L*0.22,L*0.24,t)];
p1=[W*lerp(0.10,0.17,t), lerp(-L*0.34,L*0.38,t)];
p2=[W*lerp(0.25,0.36,t), lerp(L*0.18,-L*0.12,t)];
p3=[W*lerp(0.34,0.46,t), lerp(-L*0.05,L*0.30,t)];
stroke_bezier(p0,p1,p2,p3,w*Ornamental_Styrke,16);
if(Ornamental_Ringe)
translate(p3) difference() {
circle(d=W*(0.018+0.008*t)*Ornamental_Styrke+2*w);
circle(d=max(W*(0.018+0.008*t)*Ornamental_Styrke,w));
}
}
}
}
module ornamental_2d() {
intersection() {
mirrored_pair() ornamental_half();
wings_2d();
}
}
// ------------------------------------------------------------
// Stencil bridges
// ------------------------------------------------------------
module stencil_bridges_half() {
if(Stencil_Mode) {
bw=max(Stencil_Bro_Bredde,eff_min_feature());
for(i=[0:Stencil_Bro_Antal-1]) {
t=(i+1)/(Stencil_Bro_Antal+1);
y=lerp(-eff_body_len()*0.18,eff_body_len()*0.20,t);
x0=eff_body_w()*0.25;
x1=x0+Stencil_Bro_Laengde*(0.72+0.28*t);
stroke_polyline([[x0,y],[x1,y+(t-0.5)*Stencil_Bro_Laengde*0.18]],bw);
}
}
}
module stencil_bridges_2d() {
union() {
mirrored_pair() stencil_bridges_half();
if(Stencil_Mode && Stencil_Centerbro && Ophaengshul) {
bw=max(Stencil_Bro_Bredde,eff_min_feature());
y=eff_body_len()*0.32+Ophaengshul_Y;
translate([-bw/2,y-Ophaengshul_Diameter/2-0.2]) square([bw,Ophaengshul_Diameter+0.4]);
}
}
}
// ------------------------------------------------------------
// Silhuet, udskaeringer, montage
// ------------------------------------------------------------
module cutout_pattern_half() {
if(eff_cutout()>0) {
span=Vingefang/2*0.78;
for(i=[1:3]) {
yy=lerp(-Vingefang*0.12,Vingefang*0.14,i/4);
translate([eff_body_w()/2+span*(0.25+0.16*i),yy])
scale([1.5,1]) circle(d=Vingefang*0.05*eff_cutout());
}
}
}
module silhouette_raw_2d() {
union() { wings_2d(); body_2d(); }
}
module silhouette_2d() {
union() {
difference() {
if(eff_outline()>0) offset(r=eff_outline()) offset(r=0.06) offset(delta=-0.06) silhouette_raw_2d();
else offset(r=0.06) offset(delta=-0.06) silhouette_raw_2d();
if(eff_cutout()>0)
intersection() {
offset(delta=-Udskaering_Margin) wings_2d();
union() { cutout_pattern_half(); mirror([1,0,0]) cutout_pattern_half(); }
}
if(Ophaengshul)
translate([0,eff_body_len()*0.32+Ophaengshul_Y]) circle(d=Ophaengshul_Diameter);
}
if(Stencil_Mode)
intersection() { stencil_bridges_2d(); silhouette_raw_2d(); }
}
}
module decoration_2d() {
decorations_raw_2d();
}
// ------------------------------------------------------------
// Multi-layer helpers
// ------------------------------------------------------------
module wing_layer_2d() {
if(Layer_Overlap>0) offset(delta=Layer_Overlap) wings_2d(); else wings_2d();
}
module body_layer_2d() {
if(Layer_Overlap>0) offset(delta=Layer_Overlap) body_2d(); else body_2d();
}
module spot_layer_2d() {
intersection() {
union() {
wing_spots_half(); mirror([1,0,0]) wing_spots_half();
beetle_spots_half(); mirror([1,0,0]) beetle_spots_half();
if(is_longwing()) mirrored_pair() {
pterostigma_half(+eff_long_sep()/2,Langvinge_For_Skala);
pterostigma_half(-eff_long_sep()/2,Langvinge_Bag_Skala);
}
}
wings_2d();
}
}
module vein_layer_2d() {
difference() { decoration_2d(); spot_layer_2d(); }
}
module selected_layer_2d() {
if(Layer_Output=="Vinger") wing_layer_2d();
else if(Layer_Output=="Krop") body_layer_2d();
else if(Layer_Output=="Aarer") vein_layer_2d();
else if(Layer_Output=="Pletter") spot_layer_2d();
else if(Layer_Output=="Stencilbroer") stencil_bridges_2d();
else union() { silhouette_2d(); decoration_2d(); }
}
// ------------------------------------------------------------
// Panel / batch layout
// ------------------------------------------------------------
module panelize() {
for(r=[0:Panel_Raekker-1])
for(c=[0:Panel_Kolonner-1]) {
idx=r*Panel_Kolonner+c;
tx=(c-(Panel_Kolonner-1)/2)*Panel_Afstand_X;
ty=((Panel_Raekker-1)/2-r)*Panel_Afstand_Y;
translate([tx,ty,0])
rotate(idx%2==1 ? Panel_Skiftevis_Rotation : 0)
if(Panel_Skiftevis_Spejling && idx%2==1) mirror([1,0,0]) children();
else children();
}
}
// ------------------------------------------------------------
// 3D
// ------------------------------------------------------------
module extrude_soft(height=2) {
linear_extrude(height=height) children();
}
module model_3d_flat() {
extrude_soft(Tykkelse) silhouette_2d();
}
module model_3d_relief() {
if(Relief_Haevede_Detaljer) {
union() {
extrude_soft(Tykkelse) silhouette_2d();
translate([0,0,Tykkelse-EPS])
linear_extrude(height=Relief_Hoejde+EPS)
intersection() { decoration_2d(); silhouette_2d(); }
}
} else {
difference() {
extrude_soft(Tykkelse) silhouette_2d();
translate([0,0,max(0,Tykkelse-Relief_Hoejde)])
linear_extrude(height=Relief_Hoejde+EPS*2)
intersection() { decoration_2d(); silhouette_2d(); }
}
}
}
// ------------------------------------------------------------
// Top-level output
// ------------------------------------------------------------
module single_output() {
if(Output=="2D_SILHOUET")
if(Layer_Output=="Alle") silhouette_2d(); else selected_layer_2d();
else if(Output=="2D_DEKORATION")
if(Layer_Output=="Alle") decoration_2d(); else selected_layer_2d();
else if(Output=="2D_COMBINED")
if(Layer_Output=="Alle") union() { silhouette_2d(); decoration_2d(); } else selected_layer_2d();
else if(Output=="3D_FLAT")
model_3d_flat();
else
model_3d_relief();
}
if(Panel_Mode)
panelize() single_output();
else
single_output();
if(Vis_Centerlinje && $preview && !Panel_Mode)
color("red") translate([-0.15,-eff_body_len()/2,0]) square([0.3,eff_body_len()]);