Tree Gen 1.33.0: Hoehen-Filter - der Setzling bekommt einen freien Fuss
Befund aus der Turnhalle: die Setzlings-Blaetter verteilen sich ueber die ganze
Stammhoehe, es entsteht eine belaubte Saeule statt einer Krone. Nachgemessen:
44 % der Cards sassen unter 40 % der Baumhoehe, die tiefste bei 6 %.
Der Radius-Filter kann das nicht loesen - er trennt duenn von dick, aber ein
junger Stamm ist UEBERALL duenn. Also ein zweiter Filter ueber die Hoehe: Laub
erst ab dem Kronenansatz, als Anteil der Baumhoehe. Die Schwelle kommt aus der
Bounding Box des Baums, nicht als Meterwert - fest waere sie beim Setzling die
halbe Pflanze und beim Altbaum wirkungslos.
Kronenansatz je Stufe (LEAF_STUFEN): S1 40 %, S2 35 %, S3 30 %, S4 25 %.
unter Ansatz tiefste Card
vorher nachher vorher nachher
S1 44 % 0 % 6 % 46 %
S2 32 % 0 % 24 % 36 %
S3 9 % 0 % 31 % 34 %
S4 3 % 0 % 34 % 34 % (unveraendert)
Beim Altbaum ist der Filter praktisch ein Sicherheitsnetz - dort sitzt ohnehin
nichts tief, genau wie gemeldet.
Dichte von S1/S2 nachgezogen: der Filter nimmt dem Setzling sonst die Haelfte
der Cards (9 -> 4), weil dessen Laub vorher ueber die ganze Stammhoehe verteilt
war. Jetzt 11 Cards bei S1, und 486 Tris gegen 800 Budget.
23 Tests bestehen (Suite zweimal durchlaufen).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -416,6 +416,24 @@ ohne Anhebung bekaeme er null Cards. Was zaehlt, ist die Anzahl:
|
|||||||
| S3 | 67 | 0.37 | 946 | 4300 |
|
| S3 | 67 | 0.37 | 946 | 4300 |
|
||||||
| S4 | 130 | 0.45 | 1396 | 4300 |
|
| S4 | 130 | 0.45 | 1396 | 4300 |
|
||||||
|
|
||||||
|
**Der Hoehen-Filter haelt den Fuss frei.** Der Radius-Filter allein reicht
|
||||||
|
nicht: er trennt duenn von dick, aber ein junger Stamm ist *ueberall* duenn.
|
||||||
|
Gemessen sassen beim Setzling **44 %** der Cards unter 40 % der Baumhoehe, die
|
||||||
|
tiefste bei **6 %** — eine belaubte Saeule statt einer Krone. Der Kronenansatz
|
||||||
|
steht deshalb je Stufe in `LEAF_STUFEN` (Anteil der Baumhoehe, aus der Bounding
|
||||||
|
Box abgeleitet — ein fester Meterwert waere beim Setzling die halbe Pflanze):
|
||||||
|
|
||||||
|
| Stufe | Ansatz | unter Ansatz vorher | nachher | tiefste Card |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| S1 | 40 % | 44 % | **0 %** | 6 % → **46 %** |
|
||||||
|
| S2 | 35 % | 32 % | **0 %** | 24 % → 36 % |
|
||||||
|
| S3 | 30 % | 9 % | **0 %** | 31 % → 34 % |
|
||||||
|
| S4 | 25 % | 3 % | **0 %** | 34 % (unveraendert) |
|
||||||
|
|
||||||
|
Beim Altbaum ist der Filter praktisch ein Sicherheitsnetz — dort sitzt ohnehin
|
||||||
|
nichts tief. Die Dichte von S1/S2 wurde nachgezogen, weil der Filter dem
|
||||||
|
Setzling sonst die Haelfte der Cards nimmt.
|
||||||
|
|
||||||
**Der Radius-Filter skaliert mit.** Er trennt duenne Zweige (Laub) von dickem
|
**Der Radius-Filter skaliert mit.** Er trennt duenne Zweige (Laub) von dickem
|
||||||
Geaest — aber ein Setzling ist *komplett* duenner als eine feste Schwelle. Mit
|
Geaest — aber ein Setzling ist *komplett* duenner als eine feste Schwelle. Mit
|
||||||
starren 0.04 m sassen bei S2 **81 %** der Cards am Stamm, bei S3 58 %; jetzt
|
starren 0.04 m sassen bei S2 **81 %** der Cards am Stamm, bei S3 58 %; jetzt
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
schema_version = "1.0.0"
|
schema_version = "1.0.0"
|
||||||
|
|
||||||
id = "stylized_tree_generator"
|
id = "stylized_tree_generator"
|
||||||
version = "1.32.0"
|
version = "1.33.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.32.0.zip?repository=.%2Findex.json&blender_version_min=4.2.0">stylized_tree_generator-1.32.0</a></tt></td>
|
<td><tt><a href="./stylized_tree_generator-1.33.0.zip?repository=.%2Findex.json&blender_version_min=4.2.0">stylized_tree_generator-1.33.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>37.8KB</td>
|
<td>38.5KB</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<center><p>Built 2026-08-06, 07:44</p></center>
|
<center><p>Built 2026-08-06, 08:08</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.32.0",
|
"version": "1.33.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.32.0.zip",
|
"archive_url": "./stylized_tree_generator-1.33.0.zip",
|
||||||
"archive_size": 38712,
|
"archive_size": 39431,
|
||||||
"archive_hash": "sha256:b92b7caccf18b7690b63cee35b8597484a0a789d47a9df529857d23bbf57be8f"
|
"archive_hash": "sha256:757cecfccbac8f1a50eadd62d47b9439d98550ad2f0677604ed6832610fd74f8"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
+54
-11
@@ -1,7 +1,7 @@
|
|||||||
bl_info = {
|
bl_info = {
|
||||||
"name": "Stylized Tree Generator",
|
"name": "Stylized Tree Generator",
|
||||||
"author": "D4rkst3r",
|
"author": "D4rkst3r",
|
||||||
"version": (1, 32, 0),
|
"version": (1, 33, 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",
|
||||||
@@ -1202,6 +1202,7 @@ LEAF_DEFAULTS = {
|
|||||||
# UE gegengeprueft, nicht geschaetzt.
|
# UE gegengeprueft, nicht geschaetzt.
|
||||||
"Max Radius": 0.04,
|
"Max Radius": 0.04,
|
||||||
"Size": 0.85,
|
"Size": 0.85,
|
||||||
|
"Min Height": 0.25, # Kronenansatz als Anteil der Baumhoehe
|
||||||
"Size Var": 0.35,
|
"Size Var": 0.35,
|
||||||
"Tilt": 0.9, # mehr Rotations-Chaos schliesst Sichtluecken
|
"Tilt": 0.9, # mehr Rotations-Chaos schliesst Sichtluecken
|
||||||
"Seed": 0,
|
"Seed": 0,
|
||||||
@@ -1248,6 +1249,11 @@ def build_leaf_group(rebuild=False):
|
|||||||
add_in("Use Collection", 'NodeSocketBool', False)
|
add_in("Use Collection", 'NodeSocketBool', False)
|
||||||
add_in("Density", 'NodeSocketFloat', LEAF_DEFAULTS["Density"], 0.0, 20000.0)
|
add_in("Density", 'NodeSocketFloat', LEAF_DEFAULTS["Density"], 0.0, 20000.0)
|
||||||
add_in("Max Radius", 'NodeSocketFloat', LEAF_DEFAULTS["Max Radius"], 0.001, 0.5)
|
add_in("Max Radius", 'NodeSocketFloat', LEAF_DEFAULTS["Max Radius"], 0.001, 0.5)
|
||||||
|
# Kronenansatz als ANTEIL der Baumhoehe. Der Radius-Filter allein reicht
|
||||||
|
# nicht: er trennt duenn von dick, aber ein junger Stamm ist ueberall duenn -
|
||||||
|
# gemessen sassen beim Setzling 44 % der Cards unter 40 % der Hoehe, die
|
||||||
|
# tiefste bei 6 %. Das ergibt eine belaubte Saeule statt einer Krone.
|
||||||
|
add_in("Min Height", 'NodeSocketFloat', LEAF_DEFAULTS["Min Height"], 0.0, 0.95)
|
||||||
add_in("Size", 'NodeSocketFloat', LEAF_DEFAULTS["Size"], 0.01, 5.0)
|
add_in("Size", 'NodeSocketFloat', LEAF_DEFAULTS["Size"], 0.01, 5.0)
|
||||||
add_in("Size Var", 'NodeSocketFloat', LEAF_DEFAULTS["Size Var"], 0.0, 1.0)
|
add_in("Size Var", 'NodeSocketFloat', LEAF_DEFAULTS["Size Var"], 0.0, 1.0)
|
||||||
add_in("Tilt", 'NodeSocketFloat', LEAF_DEFAULTS["Tilt"], 0.0, 3.14159)
|
add_in("Tilt", 'NodeSocketFloat', LEAF_DEFAULTS["Tilt"], 0.0, 3.14159)
|
||||||
@@ -1289,9 +1295,39 @@ def build_leaf_group(rebuild=False):
|
|||||||
L(_out(na, "Attribute"), cmp.inputs[0])
|
L(_out(na, "Attribute"), cmp.inputs[0])
|
||||||
L(V["Max Radius"], cmp.inputs[1])
|
L(V["Max Radius"], cmp.inputs[1])
|
||||||
|
|
||||||
|
# HOEHEN-FILTER: erst ab dem Kronenansatz. Die Schwelle wird aus der
|
||||||
|
# Bounding Box des Baums abgeleitet, damit sie fuer jede Groesse stimmt -
|
||||||
|
# ein fester Meterwert waere beim Setzling die halbe Pflanze.
|
||||||
|
bb = N("GeometryNodeBoundBox"); bb.location = (-700, -60)
|
||||||
|
L(_out(tree, "Geometry"), _sock(bb, "Geometry"))
|
||||||
|
bmin = N("ShaderNodeSeparateXYZ"); bmin.location = (-560, -60)
|
||||||
|
L(_out(bb, "Min"), bmin.inputs[0])
|
||||||
|
bmax = N("ShaderNodeSeparateXYZ"); bmax.location = (-560, -140)
|
||||||
|
L(_out(bb, "Max"), bmax.inputs[0])
|
||||||
|
bh = N("ShaderNodeMath"); bh.location = (-420, -100); bh.operation = 'SUBTRACT'
|
||||||
|
L(bmax.outputs["Z"], bh.inputs[0]); L(bmin.outputs["Z"], bh.inputs[1])
|
||||||
|
bmul = N("ShaderNodeMath"); bmul.location = (-280, -100); bmul.operation = 'MULTIPLY'
|
||||||
|
L(bh.outputs[0], bmul.inputs[0]); L(V["Min Height"], bmul.inputs[1])
|
||||||
|
bschwelle = N("ShaderNodeMath"); bschwelle.location = (-140, -100)
|
||||||
|
bschwelle.operation = 'ADD'
|
||||||
|
L(bmin.outputs["Z"], bschwelle.inputs[0]); L(bmul.outputs[0], bschwelle.inputs[1])
|
||||||
|
|
||||||
|
hpos = N("GeometryNodeInputPosition"); hpos.location = (-560, -220)
|
||||||
|
hsep = N("ShaderNodeSeparateXYZ"); hsep.location = (-420, -220)
|
||||||
|
L(hpos.outputs[0], hsep.inputs[0])
|
||||||
|
hcmp = N("FunctionNodeCompare"); hcmp.location = (-140, -220)
|
||||||
|
hcmp.data_type = 'FLOAT'; hcmp.operation = 'GREATER_THAN'
|
||||||
|
L(hsep.outputs["Z"], hcmp.inputs[0])
|
||||||
|
L(bschwelle.outputs[0], hcmp.inputs[1])
|
||||||
|
|
||||||
|
beide = N("FunctionNodeBooleanMath"); beide.location = (0, 20)
|
||||||
|
beide.operation = 'AND'
|
||||||
|
L(cmp.outputs[0], beide.inputs[0])
|
||||||
|
L(hcmp.outputs[0], beide.inputs[1])
|
||||||
|
|
||||||
dist = N("GeometryNodeDistributePointsOnFaces"); dist.location = (-320, 200)
|
dist = N("GeometryNodeDistributePointsOnFaces"); dist.location = (-320, 200)
|
||||||
L(_out(tree, "Geometry"), _sock(dist, "Mesh"))
|
L(_out(tree, "Geometry"), _sock(dist, "Mesh"))
|
||||||
L(cmp.outputs[0], _sock(dist, "Selection"))
|
L(beide.outputs[0], _sock(dist, "Selection"))
|
||||||
L(V["Density"], _sock(dist, "Density"))
|
L(V["Density"], _sock(dist, "Density"))
|
||||||
L(V["Seed"], _sock(dist, "Seed"))
|
L(V["Seed"], _sock(dist, "Seed"))
|
||||||
|
|
||||||
@@ -1398,16 +1434,20 @@ def leaf_socket_ids(ng):
|
|||||||
LEAF_RADIUS_YOUNG = 0.20
|
LEAF_RADIUS_YOUNG = 0.20
|
||||||
|
|
||||||
# Dichte-Anteil Groessen-Anteil
|
# Dichte-Anteil Groessen-Anteil
|
||||||
|
# Dichte Groesse Kronenansatz
|
||||||
LEAF_STUFEN = (
|
LEAF_STUFEN = (
|
||||||
(6.00, 0.45), # S1 - wenige, kleine Bueschel auf winziger Zweigflaeche
|
# S1/S2 Dichte nachgezogen, nachdem der Hoehen-Filter dazukam: er nimmt dem
|
||||||
(1.60, 0.63), # S2 - 15 % unter der vollen Deckung (nach Flaeche gerechnet)
|
# Setzling die Haelfte der Cards (9 -> 4), weil dessen Laub vorher ueber die
|
||||||
(1.00, 0.82), # S3
|
# ganze Stammhoehe verteilt war.
|
||||||
(1.00, 1.00), # S4 - volle Dichte
|
(13.0, 0.45, 0.40), # S1 - wenige kleine Bueschel, Fuss bleibt frei
|
||||||
|
(2.10, 0.63, 0.35), # S2
|
||||||
|
(1.00, 0.82, 0.30), # S3
|
||||||
|
(1.00, 1.00, 0.25), # S4 - Sicherheitsnetz, hier sitzt ohnehin nichts tief
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _stufen_anteile(growth_t):
|
def _stufen_anteile(growth_t):
|
||||||
"""Dichte- und Groessen-Anteil fuer einen Wachstums-Fortschritt.
|
"""Dichte-, Groessen- und Kronenansatz-Wert fuer einen Wachstums-Fortschritt.
|
||||||
|
|
||||||
Die Stufen liegen bei t = 0 / 1/3 / 2/3 / 1 (vier Stufen). Zwischen den
|
Die Stufen liegen bei t = 0 / 1/3 / 2/3 / 1 (vier Stufen). Zwischen den
|
||||||
Stuetzstellen wird linear gemischt, damit auch drei oder fuenf Stufen
|
Stuetzstellen wird linear gemischt, damit auch drei oder fuenf Stufen
|
||||||
@@ -1417,9 +1457,11 @@ def _stufen_anteile(growth_t):
|
|||||||
x = max(0.0, min(1.0, growth_t)) * (n - 1)
|
x = max(0.0, min(1.0, growth_t)) * (n - 1)
|
||||||
i = min(int(x), n - 2)
|
i = min(int(x), n - 2)
|
||||||
f = x - i
|
f = x - i
|
||||||
d0, g0 = LEAF_STUFEN[i]
|
d0, g0, h0 = LEAF_STUFEN[i]
|
||||||
d1, g1 = LEAF_STUFEN[i + 1]
|
d1, g1, h1 = LEAF_STUFEN[i + 1]
|
||||||
return d0 + (d1 - d0) * f, g0 + (g1 - g0) * f
|
return (d0 + (d1 - d0) * f,
|
||||||
|
g0 + (g1 - g0) * f,
|
||||||
|
h0 + (h1 - h0) * f)
|
||||||
|
|
||||||
|
|
||||||
def _stufen_budget(s, growth_t):
|
def _stufen_budget(s, growth_t):
|
||||||
@@ -2554,7 +2596,7 @@ class TREEGEN_OT_leaves(Operator):
|
|||||||
# traegt kleinere Bueschel. Baeume ohne Wachstums-Stufe haben
|
# traegt kleinere Bueschel. Baeume ohne Wachstums-Stufe haben
|
||||||
# growth_t = 1.0 und bleiben unveraendert.
|
# growth_t = 1.0 und bleiben unveraendert.
|
||||||
gt = float(t.get("growth_t", 1.0))
|
gt = float(t.get("growth_t", 1.0))
|
||||||
d_anteil, g_anteil = _stufen_anteile(gt)
|
d_anteil, g_anteil, h_anteil = _stufen_anteile(gt)
|
||||||
|
|
||||||
# Der RADIUS-FILTER muss mit dem Baum schrumpfen. Er trennt
|
# Der RADIUS-FILTER muss mit dem Baum schrumpfen. Er trennt
|
||||||
# duenne Zweige (Laub) von dickem Geaest (kein Laub) - aber ein
|
# duenne Zweige (Laub) von dickem Geaest (kein Laub) - aber ein
|
||||||
@@ -2575,6 +2617,7 @@ class TREEGEN_OT_leaves(Operator):
|
|||||||
Size=s.leaf_size * g_anteil,
|
Size=s.leaf_size * g_anteil,
|
||||||
**{"Size Var": s.leaf_size_var,
|
**{"Size Var": s.leaf_size_var,
|
||||||
"Max Radius": s.leaf_max_radius * r_faktor,
|
"Max Radius": s.leaf_max_radius * r_faktor,
|
||||||
|
"Min Height": h_anteil,
|
||||||
"Tilt": s.leaf_tilt, "Seed": s.seed})
|
"Tilt": s.leaf_tilt, "Seed": s.seed})
|
||||||
except Exception as exc: # noqa: BLE001
|
except Exception as exc: # noqa: BLE001
|
||||||
self.report({'WARNING'}, "%s: %s" % (t.name, exc))
|
self.report({'WARNING'}, "%s: %s" % (t.name, exc))
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ if not (130.0 <= s.leaf_density <= 200.0):
|
|||||||
% s.leaf_density)
|
% s.leaf_density)
|
||||||
# Die Deckung steht als Tabelle pro Stufe, nicht als Formel. Card-ANZAHL muss
|
# Die Deckung steht als Tabelle pro Stufe, nicht als Formel. Card-ANZAHL muss
|
||||||
# ueber die Stufen steigen, Card-Groesse auch.
|
# ueber die Stufen steigen, Card-Groesse auch.
|
||||||
_d0, _g0 = tg._stufen_anteile(0.0)
|
_d0, _g0, _h0 = tg._stufen_anteile(0.0)
|
||||||
_d1, _g1 = tg._stufen_anteile(1.0)
|
_d1, _g1, _h1 = tg._stufen_anteile(1.0)
|
||||||
if _g0 >= _g1:
|
if _g0 >= _g1:
|
||||||
fails.append("Groessen-Anteil steigt nicht ueber die Stufen (%.2f -> %.2f)"
|
fails.append("Groessen-Anteil steigt nicht ueber die Stufen (%.2f -> %.2f)"
|
||||||
% (_g0, _g1))
|
% (_g0, _g1))
|
||||||
@@ -193,6 +193,61 @@ if kanten and kanten[0] > 0:
|
|||||||
"steht auf %.0f%% - die Wachstums-Kopplung greift nicht"
|
"steht auf %.0f%% - die Wachstums-Kopplung greift nicht"
|
||||||
% (100 * anteil, 100 * s.leaf_size_growth))
|
% (100 * anteil, 100 * s.leaf_size_growth))
|
||||||
|
|
||||||
|
# --- 3a) Hoehen-Filter: der Fuss bleibt frei -----------------------------
|
||||||
|
# Der Radius-Filter allein reicht nicht. Er trennt duenn von dick, aber ein
|
||||||
|
# junger Stamm ist UEBERALL duenn - gemessen sassen beim Setzling 44 % der
|
||||||
|
# Cards unter 40 % der Hoehe, die tiefste bei 6 %. Das ergibt eine belaubte
|
||||||
|
# Saeule statt einer Krone. Der Hoehen-Filter setzt den Kronenansatz je Stufe.
|
||||||
|
print("")
|
||||||
|
print("%-18s %7s %6s %11s %11s" % ("Stufe", "Hoehe", "Cards", "unter Ansatz",
|
||||||
|
"tiefste Card"))
|
||||||
|
for st in staemme:
|
||||||
|
bl = bpy.data.objects.get(st.name + "_Leaf")
|
||||||
|
if bl is None:
|
||||||
|
continue
|
||||||
|
zs = [v.co.z for v in st.data.vertices]
|
||||||
|
z0, h = min(zs), max(zs) - min(zs)
|
||||||
|
gt = float(st.get("growth_t", 1.0))
|
||||||
|
_, _, ansatz = tg._stufen_anteile(gt)
|
||||||
|
|
||||||
|
dg = bpy.context.evaluated_depsgraph_get()
|
||||||
|
ev = bl.evaluated_get(dg)
|
||||||
|
m = ev.to_mesh()
|
||||||
|
# Card-Mitten ueber die Face-Gruppen (die Testkarte hat 2 Faces je Card)
|
||||||
|
proc = 2
|
||||||
|
mitten = []
|
||||||
|
for i in range(0, len(m.polygons), proc):
|
||||||
|
gruppe = m.polygons[i:i + proc]
|
||||||
|
mitten.append(sum(p.center.z for p in gruppe) / len(gruppe))
|
||||||
|
ev.to_mesh_clear()
|
||||||
|
if not mitten:
|
||||||
|
continue
|
||||||
|
|
||||||
|
unter = 100.0 * sum(1 for z in mitten if (z - z0) / h < ansatz) / len(mitten)
|
||||||
|
tiefste = 100.0 * (min(mitten) - z0) / h
|
||||||
|
print("%-18s %7.2f %6d %9.0f%% %10.0f%%"
|
||||||
|
% (st.name, h, len(mitten), unter, tiefste))
|
||||||
|
|
||||||
|
# Ein paar Prozent Toleranz: die Card-Mitte darf leicht unter den Ansatz
|
||||||
|
# rutschen, weil die Card um ihren Punkt herum sitzt.
|
||||||
|
if unter > 15.0:
|
||||||
|
fails.append("%s: %.0f%% der Cards unter dem Kronenansatz (%.0f%% der "
|
||||||
|
"Hoehe) - der Fuss ist belaubt" % (st.name, unter,
|
||||||
|
100 * ansatz))
|
||||||
|
if tiefste < ansatz * 100 * 0.7:
|
||||||
|
fails.append("%s: tiefste Card bei %.0f%% der Hoehe, Kronenansatz liegt "
|
||||||
|
"bei %.0f%% - Laub klebt am Stamm"
|
||||||
|
% (st.name, tiefste, 100 * ansatz))
|
||||||
|
|
||||||
|
# Der Ansatz muss beim Setzling HOEHER liegen als beim Altbaum: dessen
|
||||||
|
# Verteilung passt schon von selbst, der Setzling braucht die Hilfe.
|
||||||
|
_, _, a_jung = tg._stufen_anteile(0.0)
|
||||||
|
_, _, a_alt = tg._stufen_anteile(1.0)
|
||||||
|
print("Kronenansatz: S1 %.0f%%, S4 %.0f%%" % (100 * a_jung, 100 * a_alt))
|
||||||
|
if a_jung <= a_alt:
|
||||||
|
fails.append("Kronenansatz beim Setzling (%.2f) nicht hoeher als beim "
|
||||||
|
"Altbaum (%.2f)" % (a_jung, a_alt))
|
||||||
|
|
||||||
# --- 3b) Budget je Stufe statt global -----------------------------------
|
# --- 3b) Budget je Stufe statt global -----------------------------------
|
||||||
print("")
|
print("")
|
||||||
print("%-18s %6s %8s %8s" % ("Stufe", "t", "Tris", "Budget"))
|
print("%-18s %6s %8s %8s" % ("Stufe", "t", "Tris", "Budget"))
|
||||||
|
|||||||
Reference in New Issue
Block a user