Tree Gen 1.40.0: Obstbaum-Krone schliesst sich oben (Trichter behoben)
Der Baum erfuellte Kronenradius, Deckung, Kronenansatz und Tri-Budget - und sah trotzdem falsch aus. Sichtbar wurde es erst am BREITENPROFIL der Krone in Dritteln (unten/mitte/oben, Messung der Spielseite nachgestellt): Eiche 3.0 / 2.8 / 2.6 oben/mitte 0.90 (liest sich als Baum) Obstbaum 3.3 / 4.5 / 4.7 oben/mitte 1.07 (Trichter) Kein einzelner Regler hat das geloest: Crown Taper (-0.10 bis +0.50), Branch Droop (0.6-1.2), Crown Bulge (1.0-1.8) und Attraction Up einzeln durchgefahren liessen oben/mitte bei rund 1.0 stehen. Der Grund ist strukturell: die Kronenform folgt nicht der Astlaenge je Hoehe, sondern dem WEG DER ASTSPITZEN. Solange die Aeste aufwaerts schwingen, landet das aeusserste Laub oben. Loesung ist eine andere Bauform, kein Feintuning - kurze Aeste an einem hohen Stamm statt langer Aeste an einem kurzen: Height 3.8 -> 4.9, Branch Length 2.55 -> 1.25, Branch Start 0.52 -> 0.40, Attraction Up +0.40 -> -0.05, Crown Taper -0.30 -> +0.15, Crown Bulge 0.60 -> 1.10, Branch Droop 0.35 -> 0.40. Ueber alle neun Produktions-Seeds: oben/mitte 0.63-0.84, Kronenradius 1.88-2.01 m, Deckung 100-134 % der Eiche, 3752-4166 Tris, Ansatz 39 %. Beim Einregeln kippte die Form zwischendurch in eine PILZform (unten am breitesten) - deshalb steht das Profil jetzt als Test da. test_obstbaum prueft oben/mitte <= 0.85. Gegenprobe mit den 1.39er Werten: neun Fehler bei 0.98-1.11. B/H liegt jetzt bei 0.77-0.82 (Band der Spielseite 0.55-0.75). Bleibt bewusst ungeprueft, wie beim Kronenradius entschieden: die Vorgaben Kronenradius >= 1.80 und B/H <= 0.75 sind bei 4-5 m Hoehe nur im Mittel gleichzeitig erfuellbar. 26 Tests bestehen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -563,6 +563,41 @@ Der Kaktus erzeugt regulaer **0 Cards** — kein Ast ist duenner als `Max Radius
|
|||||||
und das ist botanisch richtig. Vorher lief das still durch und man stand vor
|
und das ist botanisch richtig. Vorher lief das still durch und man stand vor
|
||||||
einer leeren `_Leaf`-Ebene; jetzt sagt der Operator es und nennt den Regler.
|
einer leeren `_Leaf`-Ebene; jetzt sagt der Operator es und nennt den Regler.
|
||||||
|
|
||||||
|
### Obstbaum-Silhouette: Trichter statt Krone
|
||||||
|
|
||||||
|
Der Baum erfuellte Kronenradius, Deckung, Ansatz und Tri-Budget - und sah
|
||||||
|
trotzdem falsch aus. Gemessen wurde das erst am BREITENPROFIL der Krone in
|
||||||
|
Dritteln (unten/mitte/oben):
|
||||||
|
|
||||||
|
| | unten | mitte | oben | oben/mitte |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| Eiche (liest sich als Baum) | 3.0 | 2.8 | 2.6 | **0.90** |
|
||||||
|
| Obstbaum vorher | 3.3 | 4.5 | 4.7 | **1.07** |
|
||||||
|
|
||||||
|
Nach oben BREITER: die Laubmasse sass an den top-aussen endenden Astspitzen,
|
||||||
|
unten war die Krone hohl. Ein Trichter, keine Krone.
|
||||||
|
|
||||||
|
Kein einzelner Regler hat das geloest - `Crown Taper`, `Branch Droop`,
|
||||||
|
`Crown Bulge` und `Attraction Up` einzeln durchgefahren liessen das Verhaeltnis
|
||||||
|
bei rund 1.0 stehen. Der Grund: die Kronenform folgt nicht der Astlaenge je
|
||||||
|
Hoehe, sondern dem WEG DER ASTSPITZEN. Solange die Aeste aufwaerts schwingen
|
||||||
|
(`Attraction Up` positiv), landet das aeusserste Laub oben - egal wie die
|
||||||
|
Laengen verteilt sind.
|
||||||
|
|
||||||
|
Die Loesung ist eine andere Bauform, kein Feintuning: **kurze Aeste an einem
|
||||||
|
hohen Stamm** (Height 3.8 -> 4.9, Branch Length 2.55 -> 1.25) statt langer
|
||||||
|
Aeste an einem kurzen. Dazu `Attraction Up` +0.40 -> -0.05 (kein Aufschwung),
|
||||||
|
`Crown Taper` -0.30 -> +0.15 (oben kuerzere Aeste) und `Crown Bulge` 0.60 ->
|
||||||
|
1.10 (Bauch in der Mitte).
|
||||||
|
|
||||||
|
Ueber alle neun Produktions-Seeds: oben/mitte **0.63-0.84**, Kronenradius
|
||||||
|
1.88-2.01 m, Deckung 100-134 % der Eiche, 3752-4166 Tris, Kronenansatz 39 %.
|
||||||
|
|
||||||
|
Beim Einregeln kippte die Form zwischendurch in eine PILZform (unten am
|
||||||
|
breitesten, u/m 1.17) - deshalb steht das Profil jetzt als Test da und nicht
|
||||||
|
als Kommentar. `tests/test_obstbaum.py` prueft oben/mitte <= 0.85; Gegenprobe
|
||||||
|
mit den Werten aus 1.39 meldet neun Fehler bei 0.98-1.11.
|
||||||
|
|
||||||
### Kronenfuellung: es zaehlt die Flaeche, nicht die Card-Zahl
|
### Kronenfuellung: es zaehlt die Flaeche, nicht die Card-Zahl
|
||||||
|
|
||||||
Der Obstbaum las sich in der Engine als einzelne belaubte Ast-Schlaeuche mit
|
Der Obstbaum las sich in der Engine als einzelne belaubte Ast-Schlaeuche mit
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
schema_version = "1.0.0"
|
schema_version = "1.0.0"
|
||||||
|
|
||||||
id = "stylized_tree_generator"
|
id = "stylized_tree_generator"
|
||||||
version = "1.39.0"
|
version = "1.40.0"
|
||||||
name = "Stylized Tree Generator"
|
name = "Stylized Tree Generator"
|
||||||
tagline = "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen"
|
tagline = "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen"
|
||||||
maintainer = "D4rkst3r"
|
maintainer = "D4rkst3r"
|
||||||
|
|||||||
Vendored
+3
-3
@@ -50,17 +50,17 @@
|
|||||||
<td>34.1KB</td>
|
<td>34.1KB</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><tt><a href="./stylized_tree_generator-1.39.0.zip?repository=.%2Findex.json&blender_version_min=4.2.0">stylized_tree_generator-1.39.0</a></tt></td>
|
<td><tt><a href="./stylized_tree_generator-1.40.0.zip?repository=.%2Findex.json&blender_version_min=4.2.0">stylized_tree_generator-1.40.0</a></tt></td>
|
||||||
<td>Stylized Tree Generator</td>
|
<td>Stylized Tree Generator</td>
|
||||||
<td>Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen</td>
|
<td>Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen</td>
|
||||||
<td><a href="https://git.d4rkst3r.de/D4rkst3r/stylized-rock-generator">link</a></td>
|
<td><a href="https://git.d4rkst3r.de/D4rkst3r/stylized-rock-generator">link</a></td>
|
||||||
<td>4.2.0 - ~</td>
|
<td>4.2.0 - ~</td>
|
||||||
<td>all</td>
|
<td>all</td>
|
||||||
<td>all</td>
|
<td>all</td>
|
||||||
<td>46.0KB</td>
|
<td>45.9KB</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<center><p>Built 2026-08-06, 12:09</p></center>
|
<center><p>Built 2026-08-06, 12:32</p></center>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Vendored
+4
-4
@@ -82,7 +82,7 @@
|
|||||||
"id": "stylized_tree_generator",
|
"id": "stylized_tree_generator",
|
||||||
"name": "Stylized Tree Generator",
|
"name": "Stylized Tree Generator",
|
||||||
"tagline": "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen",
|
"tagline": "Parametrische Baeume, Palmen, Bueschen mit Wachstums-Stufen",
|
||||||
"version": "1.39.0",
|
"version": "1.40.0",
|
||||||
"type": "add-on",
|
"type": "add-on",
|
||||||
"maintainer": "D4rkst3r",
|
"maintainer": "D4rkst3r",
|
||||||
"license": [
|
"license": [
|
||||||
@@ -98,9 +98,9 @@
|
|||||||
"Mesh",
|
"Mesh",
|
||||||
"Modeling"
|
"Modeling"
|
||||||
],
|
],
|
||||||
"archive_url": "./stylized_tree_generator-1.39.0.zip",
|
"archive_url": "./stylized_tree_generator-1.40.0.zip",
|
||||||
"archive_size": 47076,
|
"archive_size": 46997,
|
||||||
"archive_hash": "sha256:44a7601ffb6cfb8004d213416cdc0fdd5592e0c2596a89ed6a32b2c06f12bb4d"
|
"archive_hash": "sha256:530a636ee2a8a6750699c482ac718cd1c16e5ee9c2da8d9c78c6efa07927db05"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+10
-12
@@ -1,7 +1,7 @@
|
|||||||
bl_info = {
|
bl_info = {
|
||||||
"name": "Stylized Tree Generator",
|
"name": "Stylized Tree Generator",
|
||||||
"author": "D4rkst3r",
|
"author": "D4rkst3r",
|
||||||
"version": (1, 39, 0),
|
"version": (1, 40, 0),
|
||||||
"blender": (4, 2, 0),
|
"blender": (4, 2, 0),
|
||||||
"location": "View3D > Sidebar > Tree Gen",
|
"location": "View3D > Sidebar > Tree Gen",
|
||||||
"description": "Parametrischer Baum-/Palmen-/Busch-Generator (Geometry Nodes) mit Wachstums-Stufen",
|
"description": "Parametrischer Baum-/Palmen-/Busch-Generator (Geometry Nodes) mit Wachstums-Stufen",
|
||||||
@@ -195,18 +195,16 @@ PRESETS = {
|
|||||||
# Und der Kronenansatz zaehlt gegen die GESAMThoehe: Branch Start 0.37 ergab
|
# Und der Kronenansatz zaehlt gegen die GESAMThoehe: Branch Start 0.37 ergab
|
||||||
# gemessen 29 %, nicht 37 %.
|
# gemessen 29 %, nicht 37 %.
|
||||||
"obstbaum": {
|
"obstbaum": {
|
||||||
"Height": 3.8, "Trunk Radius": 0.13, "Bend": 0.3, "Taper": 0.7,
|
"Height": 4.9, "Trunk Radius": 0.13, "Bend": 0.3, "Taper": 0.7,
|
||||||
"Branch Count": 9, # offene Krone: wenige Leitaeste, Licht durch
|
"Branch Count": 9, # offene Krone: wenige Leitaeste, Licht durch
|
||||||
# Bleibt bei 2.55. Die Krone zu verkleinern waere der zweite Hebel gegen
|
# Kurze Aeste an einem HOHEN Stamm. Vorher genau umgekehrt (Height 3.8,
|
||||||
# den niedrigen Fuellgrad gewesen - bei 2.35 fielen aber SECHS der neun
|
# Branch Length 2.55) - daraus wurde ein Trichter, siehe unten.
|
||||||
# Seeds unter den Kronenradius von 1.80 m, den die Frucht-Streuung
|
"Branch Length": 1.25, "Branch Up": 0.7,
|
||||||
# braucht (1.73-1.79). Ueber drei Seeds gemittelt sah es mit 1.83 noch
|
"Branch Start": 0.40, "Branch End": 0.90,
|
||||||
# gut aus; erst der Neun-Seed-Test hat es aufgedeckt.
|
"Crown Taper": 0.15, # oben kuerzere Aeste (war -0.30 = besenfoermig)
|
||||||
"Branch Length": 2.55, "Branch Up": 0.7,
|
"Crown Bulge": 1.1, # Bauch in der Mitte
|
||||||
"Branch Start": 0.52, "Branch End": 0.90,
|
"Attraction Up": -0.05, # KEIN Aufwaertsschwung mehr ...
|
||||||
"Crown Taper": -0.30, "Crown Bulge": 0.60, # rund, Bauch in der Mitte
|
"Branch Droop": 0.4, "Droop Curve": 3.0, # ... Spitzen kippen ab
|
||||||
"Attraction Up": 0.40, # Leitaeste steigen schraeg auf ...
|
|
||||||
"Branch Droop": 0.35, "Droop Curve": 3.0, # ... und bogen aussen ab
|
|
||||||
"Branch Bend": 0.9, "Branch Thickness": 0.22,
|
"Branch Bend": 0.9, "Branch Thickness": 0.22,
|
||||||
"Sub Count": 3, "Sub Length": 0.7, "Root Flare": 1.0,
|
"Sub Count": 3, "Sub Length": 0.7, "Root Flare": 1.0,
|
||||||
},
|
},
|
||||||
|
|||||||
+38
-6
@@ -127,12 +127,13 @@ print("")
|
|||||||
# Birne 3/17/24. Ein Preset, das nur bei einem Seed passt, ist keines.
|
# Birne 3/17/24. Ein Preset, das nur bei einem Seed passt, ist keines.
|
||||||
SEEDS = (1, 15, 22, 2, 16, 23, 3, 17, 24)
|
SEEDS = (1, 15, 22, 2, 16, 23, 3, 17, 24)
|
||||||
|
|
||||||
print("%-6s %7s %6s %9s %9s %9s %7s %9s"
|
print("%-6s %7s %6s %9s %9s %7s %8s %-15s %s"
|
||||||
% ("Seed", "Hoehe", "B/H", "KronR", "Card-Max", "KronR/Card", "Ansatz",
|
% ("Seed", "Hoehe", "B/H", "KronR", "KronR/Cd", "Ansatz", "m2/m3",
|
||||||
"m2/m3"))
|
"Profil u/m/o", "o/m"))
|
||||||
|
|
||||||
verh = []
|
verh = []
|
||||||
deckungen = []
|
deckungen = []
|
||||||
|
obenmitte = []
|
||||||
for seed in SEEDS:
|
for seed in SEEDS:
|
||||||
for o in list(bpy.context.scene.objects):
|
for o in list(bpy.context.scene.objects):
|
||||||
if o is not card:
|
if o is not card:
|
||||||
@@ -172,6 +173,7 @@ for seed in SEEDS:
|
|||||||
ev = bl.evaluated_get(dg)
|
ev = bl.evaluated_get(dg)
|
||||||
m2 = ev.to_mesh()
|
m2 = ev.to_mesh()
|
||||||
blatt_flaeche = sum(p.area for p in m2.polygons)
|
blatt_flaeche = sum(p.area for p in m2.polygons)
|
||||||
|
blatt_pts = [v.co.copy() for v in m2.vertices]
|
||||||
mitten = []
|
mitten = []
|
||||||
for grp in inseln(m2):
|
for grp in inseln(m2):
|
||||||
pts = [m2.vertices[i].co for i in grp]
|
pts = [m2.vertices[i].co for i in grp]
|
||||||
@@ -186,13 +188,33 @@ for seed in SEEDS:
|
|||||||
lz = [z for _x, _y, z in mitten]
|
lz = [z for _x, _y, z in mitten]
|
||||||
kron_zyl = math.pi * lr ** 2 * (max(lz) - min(lz))
|
kron_zyl = math.pi * lr ** 2 * (max(lz) - min(lz))
|
||||||
|
|
||||||
|
# BREITENPROFIL der Krone in Dritteln.
|
||||||
|
#
|
||||||
|
# Ohne diesen Check kann die Krone alle bisherigen Zahlen erfuellen und
|
||||||
|
# trotzdem falsch aussehen: der erste Obstbaum war ein TRICHTER - nach oben
|
||||||
|
# breiter, unten hohl (gemessen oben/mitte 1.07 gegen 0.90 der Eiche). Die
|
||||||
|
# Laubmasse sass an den top-aussen endenden Astspitzen. Kronenradius,
|
||||||
|
# Deckung und Tri-Zahl waren dabei alle in Ordnung.
|
||||||
|
profil = [0.0, 0.0, 0.0]
|
||||||
|
if blatt_pts:
|
||||||
|
pz = [p.z for p in blatt_pts]
|
||||||
|
pz0, pz1 = min(pz), max(pz)
|
||||||
|
drittel = (pz1 - pz0) / 3.0
|
||||||
|
for kk in range(3):
|
||||||
|
teil = [p for p in blatt_pts
|
||||||
|
if pz0 + kk * drittel <= p.z <= pz0 + (kk + 1) * drittel]
|
||||||
|
profil[kk] = 2 * max((math.hypot(p.x, p.y) for p in teil),
|
||||||
|
default=0.0)
|
||||||
|
om = profil[2] / profil[1] if profil[1] else 0.0
|
||||||
|
obenmitte.append(om)
|
||||||
|
|
||||||
v = kron_r / card_max if card_max else 0.0
|
v = kron_r / card_max if card_max else 0.0
|
||||||
verh.append(v)
|
verh.append(v)
|
||||||
deckung = blatt_flaeche / kron_zyl if kron_zyl else 0.0
|
deckung = blatt_flaeche / kron_zyl if kron_zyl else 0.0
|
||||||
deckungen.append(deckung)
|
deckungen.append(deckung)
|
||||||
print("%-6d %7.2f %6.2f %9.2f %9.2f %9.2f %6.0f%% %9.1f"
|
print("%-6d %7.2f %6.2f %9.2f %9.2f %6.0f%% %8.1f %.1f/%.1f/%.1f %.2f"
|
||||||
% (seed, hoehe, 2 * kron_r / hoehe, kron_r, card_max, v, ansatz,
|
% (seed, hoehe, 2 * kron_r / hoehe, kron_r, v, ansatz, deckung,
|
||||||
deckung))
|
profil[0], profil[1], profil[2], om))
|
||||||
|
|
||||||
# Kronen-DECKUNG: Blattflaeche je m3 Kronenvolumen.
|
# Kronen-DECKUNG: Blattflaeche je m3 Kronenvolumen.
|
||||||
#
|
#
|
||||||
@@ -218,6 +240,14 @@ for seed in SEEDS:
|
|||||||
"Ast-Schlaeuche" % (seed, deckung, EICHE,
|
"Ast-Schlaeuche" % (seed, deckung, EICHE,
|
||||||
100 * deckung / EICHE))
|
100 * deckung / EICHE))
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
if om > 0.85:
|
||||||
|
fails.append("Seed %d: Krone oben %.1f m breit, in der Mitte %.1f "
|
||||||
|
"(%.2f) - sie wird nach oben breiter statt sich zu "
|
||||||
|
"schliessen" % (seed, profil[2], profil[1], om))
|
||||||
|
|
||||||
# DIE funktionale Bedingung.
|
# DIE funktionale Bedingung.
|
||||||
if v < 1.3:
|
if v < 1.3:
|
||||||
fails.append("Seed %d: Kronenradius %.2f m bei %.2f m Card - die Krone "
|
fails.append("Seed %d: Kronenradius %.2f m bei %.2f m Card - die Krone "
|
||||||
@@ -241,6 +271,8 @@ for seed in SEEDS:
|
|||||||
# funktionale (Kronenradius), weil an ihr die Frucht-Streuung haengt.
|
# funktionale (Kronenradius), weil an ihr die Frucht-Streuung haengt.
|
||||||
print("")
|
print("")
|
||||||
print("Kronenradius/Card ueber alle Seeds: %.2f - %.2f" % (min(verh), max(verh)))
|
print("Kronenradius/Card ueber alle Seeds: %.2f - %.2f" % (min(verh), max(verh)))
|
||||||
|
print("Krone oben/mitte ueber alle Seeds: %.2f - %.2f (Eiche 0.90, "
|
||||||
|
"Trichter war 1.07)" % (min(obenmitte), max(obenmitte)))
|
||||||
print("Kronen-Deckung ueber alle Seeds: %.1f - %.1f m2/m3, Eiche %.1f "
|
print("Kronen-Deckung ueber alle Seeds: %.1f - %.1f m2/m3, Eiche %.1f "
|
||||||
"(%.0f-%.0f %%)"
|
"(%.0f-%.0f %%)"
|
||||||
% (min(deckungen), max(deckungen), EICHE,
|
% (min(deckungen), max(deckungen), EICHE,
|
||||||
|
|||||||
Reference in New Issue
Block a user