diff --git a/README.md b/README.md index 6c1faa3..b9bd123 100644 --- a/README.md +++ b/README.md @@ -702,6 +702,83 @@ Gegenprobe ohne die Boden-Klemmung: vier Fehler. Drei bestehende Tests zaehlten die Huelle als Render-Mesh mit und schlugen zu Recht an - sie filtern jetzt `UCX_`. +### Die Kronen-Huelle: Kugeln verschmelzen, dann streuen + +Der "behaarte Finger"-Look kam zurueck, weil wir einen Schritt der +Standard-Technik uebersprungen hatten. Die Produktions-Breakdowns (80.lv +"Meadows", "The Witness"-Baeume) machen es so: Kugeln auf die Aeste setzen, +sie zu EINER Kronenmasse verschmelzen, und die Cards ueber deren **Oberflaeche** +streuen. Wir hatten je Cluster eine eigene Halbkugel bestueckt - die Polster +blieben dadurch als getrennte Koerper sichtbar, ein Laubhandschuh je Ast. + +Jetzt: Kugeln instanzieren -> `Mesh to Volume` -> `Volume to Mesh` (das ist die +metaball-artige Verschmelzung) -> `Distribute Points on Faces` auf der Huelle. +Die Aeste verschwinden im Inneren der Krone. Vom User im Wald abgenommen. + +**Drei Befunde auf dem Weg, alle gemessen statt geraten:** + +`ast_id` kam nur an 3 von 10 Aesten an. Ursache war NICHT das Sampling, sondern +die Eingabe: es existierten nur **vier Cluster-Zentren auf drei Aesten**. In der +alten Bauform regelte die Bisektion die Cluster-Dichte selbst hoch; seit sie +stattdessen die Cards auf der Huelle regelt, muss der Startwert stimmen. +Sichtbar wurde das erst mit `Points to Vertices` - `to_mesh()` auf eine reine +Punktwolke liefert eine LEERE Mesh und misst nichts. Ein Messwerkzeug, das nicht +messen kann, sieht aus wie ein Befund. + +S1 stand komplett kahl. Die Reihe ueber die Stufen zeigte **0 / 20 / 41 / 109** +Zentren - allmaehlicher Abfall bis null, keine Klippe. Also die Cluster-Dichte, +nicht die Voxel-Groesse. "Dichte" heisst Kugeln je m2 ZWEIGflaeche, und die +schrumpft mit dem QUADRAT der Groesse; sie laeuft jetzt mit 1/g^2 gegen die +Baumgroesse, damit die ANZAHL konstant bleibt. Das ist die richtige Groesse: +eine Krone braucht eine bestimmte Zahl Ballen zum Verschmelzen, nicht eine +bestimmte Dichte. Damit ist die Bauform skalenfrei - kein Sonderweg fuer +Setzlinge. + +31 % der Cards lagen unter dem Kronenansatz. Die Verschmelzung weitet die Form +um bis zu einen Kugelradius nach unten, der Filter griff aber nur auf den +Zentren. Jetzt auch auf der Huelle - sonst waere der Fehler, gegen den der +Filter gebaut wurde, durch die Hintertuer zurueckgekommen. + +### Weniger Blaetter, und warum die ZAHL der richtige Hebel war + +Nach der Abnahme wollte der User "etwas weniger Blaetter". Zwei Hebel standen +zur Wahl, beide gemessen (Eiche): + +| | Cards | Tris | Blattflaeche je Huellenflaeche | +|---|---|---|---| +| vorher | 381 | 3714 | 10.36 | +| Ziel -15 % | 319 | 3342 | 8.64 | +| Cards -15 % kleiner | 381 | 3714 | 7.93 | + +Die Zahl zu senken kostet weniger Deckung UND spart 372 Dreiecke; die Cards zu +verkleinern kostet mehr Deckung (die Flaeche geht quadratisch) und spart kein +einziges. Der woertliche Wunsch war ausserdem der messbar bessere. + +### Das Formband gehoert um das Abgenommene, nicht umgekehrt + +Nach dem Umbau lag `u/m` bei 0.78-1.02 gegen eine Schranke von 0.82. Die +naheliegende Reaktion waere gewesen, die Krone auf die Zahl zu kalibrieren. +Stattdessen: alle Referenzformen unter der NEUEN Bauform neu durchmessen. + +| Form | u/m | o/m | +|---|---|---| +| Eiche | 1.04-1.16 | 0.79-0.91 | +| **abgenommen** | **0.78-1.02** | **0.68-0.79** | +| Trichter | 0.68-0.78 | 1.04-1.14 | +| Pilz | 0.59-0.90 | 0.82-0.95 | +| Haube | 0.94-1.03 | 0.71-0.78 | + +**Daraus folgt etwas Unbequemes: `u/m` trennt nichts mehr.** Der abgenommene +Bereich ueberlappt den Pilz und stoesst an den Trichter. Die 0.82 stammten aus +der Einzelkappen-Aera - dagegen zu kalibrieren haette die Krone verbogen, um +eine Zahl zu retten, die ihre Aussagekraft verloren hat. Dieselbe Falle wie beim +Kugel-Kennwert eine Runde zuvor, nur eine Kennzahl weiter. + +`o/m` trennt dagegen sauber (abgenommen bis 0.79, Pilz ab 0.82, Trichter ab +1.04) und traegt die Formpruefung jetzt allein. `u/m` wird nur noch +mitgedruckt - ein Kriterium, das die Fehlformen nicht mehr ausschliesst, ist +schlimmer als keines: es sieht aus wie ein Schutz und ist keiner. + ### Der Hochstamm muss auf JEDER Stufe stehen Bis 1.46 war am Obstbaum nur S4 kalibriert. Im Welt-Test ist der User auf einen diff --git a/blender_manifest_tree.toml b/blender_manifest_tree.toml index 18f3d39..c3c5883 100644 --- a/blender_manifest_tree.toml +++ b/blender_manifest_tree.toml @@ -1,7 +1,7 @@ schema_version = "1.0.0" id = "stylized_tree_generator" -version = "1.47.0" +version = "1.48.0" name = "Stylized Tree Generator" tagline = "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen" maintainer = "D4rkst3r" diff --git a/dist/index.html b/dist/index.html index 0d376c6..9bef1e7 100644 --- a/dist/index.html +++ b/dist/index.html @@ -50,17 +50,17 @@ 34.5KB - stylized_tree_generator-1.47.0 + stylized_tree_generator-1.48.0 Stylized Tree Generator Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen link 4.2.0 - ~ all all - 53.3KB + 55.1KB -

Built 2026-08-07, 11:33

+

Built 2026-08-07, 13:38

diff --git a/dist/index.json b/dist/index.json index e65cf41..ec2d49d 100644 --- a/dist/index.json +++ b/dist/index.json @@ -82,7 +82,7 @@ "id": "stylized_tree_generator", "name": "Stylized Tree Generator", "tagline": "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen", - "version": "1.47.0", + "version": "1.48.0", "type": "add-on", "maintainer": "D4rkst3r", "license": [ @@ -98,9 +98,9 @@ "Mesh", "Modeling" ], - "archive_url": "./stylized_tree_generator-1.47.0.zip", - "archive_size": 54533, - "archive_hash": "sha256:0c1ba47d4fe89d1c45dbff090d04feaa136bea349cd30386127bc70ab2acd8eb" + "archive_url": "./stylized_tree_generator-1.48.0.zip", + "archive_size": 56393, + "archive_hash": "sha256:90b1d48c25a595f0d8c6e0cd63722aa246914998979cbbec4f370b3a9c56a2b9" } ] } \ No newline at end of file diff --git a/dist/stylized_tree_generator-1.47.0.zip b/dist/stylized_tree_generator-1.47.0.zip deleted file mode 100644 index caa2fd0..0000000 Binary files a/dist/stylized_tree_generator-1.47.0.zip and /dev/null differ diff --git a/dist/stylized_tree_generator-1.48.0.zip b/dist/stylized_tree_generator-1.48.0.zip new file mode 100644 index 0000000..95c6942 Binary files /dev/null and b/dist/stylized_tree_generator-1.48.0.zip differ diff --git a/stylized_tree_generator.py b/stylized_tree_generator.py index dcad1ae..4a0a10a 100644 --- a/stylized_tree_generator.py +++ b/stylized_tree_generator.py @@ -1,7 +1,7 @@ bl_info = { "name": "Stylized Tree Generator", "author": "D4rkst3r", - "version": (1, 47, 0), + "version": (1, 48, 0), "blender": (4, 2, 0), "location": "View3D > Sidebar > Tree Gen", "description": "Parametrischer Baum-/Palmen-/Busch-Generator (Geometry Nodes) mit Wachstums-Stufen", @@ -1856,11 +1856,24 @@ LEAF_RADIUS_YOUNG = 0.20 # war; jetzt ist sie es nicht mehr. # # Ziel-Cards Groesse Kronenansatz +# Seit der Kronen-Huelle sitzen die Cards auf einer FLAECHE, nicht mehr im +# Volumen - die Zahl bestimmt damit direkter, wie viel Himmel durchscheint. +# +# Nach der Abnahme im Wald wollte der User "etwas weniger Blaetter". Umgesetzt +# als 15 % auf die Ziele. Gemessen an der Eiche: 381 -> 319 Cards, Blattflaeche +# je Huellenflaeche 10.4 -> 8.6, und 372 Tris gespart. +# +# Der Gegenversuch stand zur Wahl und ist gemessen worden: Cards um 15 % +# VERKLEINERN kostet mehr Deckung (10.4 -> 7.9, weil die Flaeche quadratisch +# geht) und spart kein einziges Dreieck. Die Zahl zu senken ist der ehrlichere +# Hebel - und der, den der User woertlich genannt hat. +# +# Ziel-Cards Groesse Kronenansatz LEAF_STUFEN = ( - (26, 0.24, 0.40), # S1 - EIN Bueschel, Fuss bleibt frei - (78, 0.46, 0.35), # S2 - drei - (208, 0.75, 0.30), # S3 - acht - (390, 1.00, 0.25), # S4 - rund fuenfzehn + (22, 0.24, 0.40), # S1 + (66, 0.46, 0.35), # S2 + (177, 0.75, 0.30), # S3 + (330, 1.00, 0.25), # S4 ) # AUSNAHMEN je Preset: {preset: {stufen_index: ziel_cards}}. @@ -1874,16 +1887,16 @@ LEAF_STUFEN = ( # Das macht die Tabelle preset-abhaengig - bewusst so entschieden, statt das # Budget fuer alle anzuheben: die Weide ist der Ausreisser, nicht die Regel. LEAF_STUFEN_PRESET = { - "weide": {3: 350}, + "weide": {3: 298}, # Die Birke hat mit 2100 Tris die dickste Rinde im Satz; bei 390 Cards # gemessen 4572 Tris. (4300 - 2100) / 6 = 366 Cards passen, 340 mit Luft # fuer die 15-%-Toleranz der Regelung. - "birke": {3: 340}, + "birke": {3: 289}, # Obstbaum: breite offene Krone auf kurzem Stamm gibt viel Zweigflaeche auf # wenig Hoehe - ungeregelt 4304-4400 Tris ueber drei Seeds, knapp ueber dem # Budget. Die Regelung haelt eine Toleranz von 15 %, deshalb liegt das Ziel # unter dem rechnerischen Maximum (497 Cards): 420 x 1.15 x 6 + 1316 = 4214. - "obstbaum": {3: 420}, + "obstbaum": {3: 357}, } # Card-GROESSE je Preset, als Faktor auf die eingestellte Groesse. diff --git a/tests/test_obstbaum.py b/tests/test_obstbaum.py index 69c90f6..0066830 100644 --- a/tests/test_obstbaum.py +++ b/tests/test_obstbaum.py @@ -316,26 +316,34 @@ for seed in SEEDS: # Die Krone muss sich nach OBEN schliessen. Die Eiche, die laut Abnahme als # Baum liest, kommt auf 0.90; der Trichter lag bei 1.07. 0.85 als Grenze # laesst Spielraum nach oben, schliesst den Trichter aber sicher aus. - # Die Grenzen kommen aus einer Messung ALLER Formen mit DIESEM Mass, nicht - # aus dem Wunschband - die Streuung von Seed zu Seed ist breiter als das - # Band, das die Spielseite genannt hat (u/m 0.85-0.95). Gemessen ueber neun - # Seeds: - # Eiche u/m 1.04-1.15 o/m 0.77-0.88 - # Trichter u/m 0.66-0.72 o/m 1.18-1.31 - # Haube u/m 0.99-1.13 o/m 0.69-0.80 - # Pilz u/m 0.75-0.90 o/m 0.78-0.94 - # Kugel u/m 0.86-1.01 o/m 0.63-0.74 - # Die Schranken trennen die Kugel von Trichter und Pilz; von der Haube - # trennt sie der Kugel-Kennwert weiter unten. + # Die Grenzen sind unter der KRONEN-HUELLE neu erhoben und um die Form + # gelegt, die der User im Wald ABGENOMMEN hat - nicht umgekehrt. Spannen + # ueber neun Seeds, alle mit demselben Mass: + # + # Eiche u/m 1.04-1.16 o/m 0.79-0.91 + # ABGENOMMEN u/m 0.78-1.02 o/m 0.68-0.79 + # Trichter u/m 0.68-0.78 o/m 1.04-1.14 + # Pilz u/m 0.59-0.90 o/m 0.82-0.95 + # Haube u/m 0.94-1.03 o/m 0.71-0.78 + # + # DARAUS FOLGT ETWAS UNBEQUEMES: u/m trennt unter der neuen Bauform NICHTS + # mehr. Der abgenommene Bereich (0.78-1.02) ueberlappt den Pilz (0.59-0.90) + # und stoesst an den Trichter (bis 0.78). Die fruehere 0.82-Schranke stammt + # aus der Einzelkappen-Aera; haette man dagegen kalibriert, waere die Krone + # verbogen worden, um eine Zahl zu retten, die ihre Aussagekraft verloren + # hat - derselbe Fall wie beim Kugel-Kennwert eine Runde zuvor. + # + # o/m trennt dagegen sauber: abgenommen bis 0.79, Pilz ab 0.82, Trichter ab + # 1.04. Diese eine Schranke traegt die Formpruefung, und der Kugel-Kennwert + # weiter unten trennt zusaetzlich von der Haube. if om > 0.80: fails.append("Seed %d: Krone oben %.1f m breit, in der Mitte %.1f " - "(%.2f) - sie schliesst sich oben nicht (Trichter lag bei " - "1.18-1.31)" % (seed, profil[2], profil[1], om)) - if um < 0.82: - fails.append("Seed %d: Krone unten %.1f m breit, in der Mitte %.1f " - "(%.2f) - unten zu schmal, das wird ein Pilz bzw. ein " - "Trichter (0.66-0.90)" - % (seed, profil[0], profil[1], um)) + "(%.2f) - abgenommen ist bis 0.79, darueber liegen Pilz " + "(ab 0.82) und Trichter (ab 1.04)" + % (seed, profil[2], profil[1], om)) + # u/m wird nur noch MITGEDRUCKT. Ein Kriterium, das die Fehlformen nicht + # mehr ausschliesst, ist schlimmer als keines: es sieht aus wie ein Schutz + # und ist keiner. if kugel > EICHE_KUGEL * 0.65: fails.append("Seed %d: Kugel-Kennwert %.2f, Eiche %.2f (%.0f %%) - der " "Obstbaum muss die RUNDESTE Art bleiben, Richtwert <= 65 %%" @@ -431,14 +439,14 @@ for _k, _x in enumerate(_st, 1): print("") print("Kronenradius/Card ueber alle Seeds: %.2f - %.2f" % (min(verh), max(verh))) -print("Krone unten/mitte ueber alle Seeds: %.2f - %.2f (Pilz 0.75-0.90, " - "Trichter 0.66-0.72)" % (min(untenmitte), max(untenmitte))) +print("Krone unten/mitte ueber alle Seeds: %.2f - %.2f (nur Info - trennt " + "unter der Huelle nichts mehr)" % (min(untenmitte), max(untenmitte))) print("Kugel (KronH/KronB) ueber alle Seeds: %.2f - %.2f, Eiche %.2f " "(%.0f-%.0f %% - Vorgabe <= 65 %%)" % (min(kugeln), max(kugeln), EICHE_KUGEL, 100 * min(kugeln) / EICHE_KUGEL, 100 * max(kugeln) / EICHE_KUGEL)) -print("Krone oben/mitte ueber alle Seeds: %.2f - %.2f (Trichter 1.18-1.31)" - % (min(obenmitte), max(obenmitte))) +print("Krone oben/mitte ueber alle Seeds: %.2f - %.2f (Pilz ab 0.82, " + "Trichter ab 1.04)" % (min(obenmitte), max(obenmitte))) print("Kronen-Deckung ueber alle Seeds: %.1f - %.1f m2/m3, Eiche %.1f " "(%.0f-%.0f %%)" % (min(deckungen), max(deckungen), EICHE,