Translate pie chart graph family
This commit is contained in:
parent
d85380909d
commit
50c2079ed3
8 changed files with 481 additions and 4 deletions
|
|
@ -114,6 +114,13 @@ Completed Cartesian function graph entry:
|
|||
- Toolchain note: `external/geometry-script` is patched so nested `@tree` calls
|
||||
create `GeometryNodeGroup` nodes under Blender 5.1.
|
||||
|
||||
Completed pie chart entry:
|
||||
|
||||
- `docs/research/translations/shriinivas-piechart.md`
|
||||
- Source groups: `NodeGroup`, `Pie Chart`
|
||||
- Verification: translated segment and three-slice chart match evaluated source
|
||||
geometry with sorted max vertex delta `0.0` in Blender 5.1.1.
|
||||
|
||||
## Extraction Workflow
|
||||
|
||||
1. Download one source `.blend` into an ignored experiment folder.
|
||||
|
|
|
|||
|
|
@ -96,6 +96,24 @@ This is a good control pattern. A graph can expose a broad global control like
|
|||
Use this when a graph should work plainly by default but become more expressive
|
||||
when upstream geometry brings richer attributes.
|
||||
|
||||
## Groups Can Pass Batons
|
||||
|
||||
Reusable node groups do not have to output geometry alone. They can output
|
||||
state: an angle, count, bound, accumulated offset, or any other value the next
|
||||
group needs.
|
||||
|
||||
The pie chart segment returns:
|
||||
|
||||
```text
|
||||
Curve: visible wedge geometry
|
||||
End: the angle where the next wedge should begin
|
||||
```
|
||||
|
||||
That makes the chart group a relay. Each segment runs its stretch, then passes
|
||||
the end angle forward. This is the pattern for cumulative structures: charts,
|
||||
stairs, chains, segmented shells, stacked floors, ribs, vertebrae, and anything
|
||||
where part N+1 depends on where part N stopped.
|
||||
|
||||
## Stack Abstractions Carefully
|
||||
|
||||
There are two abstraction layers available:
|
||||
|
|
|
|||
127
docs/research/translations/shriinivas-piechart.md
Normal file
127
docs/research/translations/shriinivas-piechart.md
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
# Translation: Shriinivas Pie Chart
|
||||
|
||||
## Source
|
||||
|
||||
- Repository: https://github.com/Shriinivas/geometrynodes
|
||||
- Source file: `piechart.blend`
|
||||
- Source groups:
|
||||
- `NodeGroup`
|
||||
- `Pie Chart`
|
||||
- Geometry Script recreation:
|
||||
`examples/geometry_script/shriinivas_piechart.py`
|
||||
|
||||
## Graph Family
|
||||
|
||||
The small pie chart is a nested state-passing graph. Each segment receives:
|
||||
|
||||
```text
|
||||
start angle
|
||||
value
|
||||
total
|
||||
shift distance
|
||||
materials
|
||||
```
|
||||
|
||||
It outputs:
|
||||
|
||||
```text
|
||||
segment geometry
|
||||
end angle
|
||||
```
|
||||
|
||||
The chart group chains three segment calls:
|
||||
|
||||
```text
|
||||
A starts at 0
|
||||
B starts at A.end
|
||||
C starts at B.end
|
||||
```
|
||||
|
||||
This is the new abstraction lesson: a node group can return geometry and a
|
||||
control value. The geometry is the visible slice; the control value is the baton
|
||||
passed to the next runner.
|
||||
|
||||
## Segment Map
|
||||
|
||||
Source group: `NodeGroup`
|
||||
|
||||
Geometry Script group: `VG Pie Segment`
|
||||
|
||||
Mechanism:
|
||||
|
||||
- Compute `fraction = Value / Total`.
|
||||
- Compute `sweep = fraction * tau`.
|
||||
- Compute `End = Start + sweep`.
|
||||
- Build a connected-center `Arc` from `Start` through `sweep`.
|
||||
- Fill the arc into a mesh face.
|
||||
- Extrude the face downward for pie thickness.
|
||||
- Convert `fraction * 100` to a string and append `%`.
|
||||
- Convert that string to curves, fill it, and extrude it lightly into text.
|
||||
- Use `Attribute Statistic` over the slice face's `Position` to find a center
|
||||
offset for the text.
|
||||
- Compute a shift vector at the segment midpoint:
|
||||
|
||||
```text
|
||||
mid = Start + sweep / 2
|
||||
offset = (cos(mid) * Shift, sin(mid) * Shift, 0)
|
||||
```
|
||||
|
||||
- Join text, extruded slice, and cap face.
|
||||
- Offset the joined geometry by the shift vector.
|
||||
- Return geometry plus `End`.
|
||||
|
||||
Metaphor: the segment group is a pastry cutter with a receipt printer attached.
|
||||
It cuts one wedge, stamps the percentage label near its middle, nudges the whole
|
||||
wedge outward if requested, and hands the next cutter the angle where it stopped.
|
||||
|
||||
## Chart Map
|
||||
|
||||
Source group: `Pie Chart`
|
||||
|
||||
Geometry Script group: `VG Pie Chart`
|
||||
|
||||
Mechanism:
|
||||
|
||||
- Compute `Total = A + B + C`.
|
||||
- Call `VG Pie Segment` for A with `Start = 0`.
|
||||
- Call `VG Pie Segment` for B with `Start = A.End`.
|
||||
- Call `VG Pie Segment` for C with `Start = B.End`.
|
||||
- Join the three segment geometries.
|
||||
|
||||
Metaphor: the chart group is not a shape maker. It is an accountant-conductor:
|
||||
it totals the values, cues each segment in order, and makes sure every slice
|
||||
starts where the previous one ended.
|
||||
|
||||
## Verification
|
||||
|
||||
Run:
|
||||
|
||||
```powershell
|
||||
& 'C:\Program Files (x86)\Steam\steamapps\common\Blender\blender.exe' --background '.\experiments\source-blends\shriinivas-piechart.blend' --python '.\tools\verify_piechart_translations.py'
|
||||
```
|
||||
|
||||
Results from Blender 5.1.1:
|
||||
|
||||
| Case | Vertices | Sorted max delta | Status |
|
||||
| --- | ---: | ---: | --- |
|
||||
| Segment | 319 | 0.0 | accepted |
|
||||
| Chart | 957 | 0.0 | accepted |
|
||||
|
||||
Generated groups saved and reinspected:
|
||||
|
||||
- `VG Pie Segment`: 30 nodes, 48 links.
|
||||
- `VG Pie Chart`: 8 nodes, 25 links.
|
||||
|
||||
## Lessons
|
||||
|
||||
- A reusable node group can output both visible geometry and invisible state.
|
||||
That state can drive later graph calls.
|
||||
- `Arc` with `connect_center=True` is a wedge skeleton. `Fill Curve` gives it a
|
||||
face; `Extrude Mesh` gives it thickness.
|
||||
- `Attribute Statistic` can summarize geometry to produce placement handles.
|
||||
Here, the mean position of the wedge face becomes a label anchor.
|
||||
- Text is geometry too: string operations feed `String to Curves`, then the same
|
||||
fill/extrude/material pipeline applies.
|
||||
- Charts and other sequential structures often need cumulative scalar flow.
|
||||
In Geometry Script, nested `@tree` calls make that flow readable as ordinary
|
||||
Python variable passing.
|
||||
145
examples/geometry_script/shriinivas_piechart.py
Normal file
145
examples/geometry_script/shriinivas_piechart.py
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
"""Geometry Script recreation of the small pie chart from Shriinivas/piechart.blend."""
|
||||
|
||||
try:
|
||||
from tools.geometry_script_loader import load_repo_geometry_script
|
||||
except ModuleNotFoundError:
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
|
||||
from tools.geometry_script_loader import load_repo_geometry_script
|
||||
|
||||
load_repo_geometry_script()
|
||||
|
||||
from geometry_script import * # noqa: F403 - Geometry Script exposes node functions as DSL globals.
|
||||
|
||||
TAU = 6.2831854820251465
|
||||
|
||||
|
||||
@tree("VG Pie Segment")
|
||||
def vg_pie_segment(
|
||||
start: Float = TAU,
|
||||
value: Float = 0.5,
|
||||
total: Float = 0.5,
|
||||
shift: Float = 0.5,
|
||||
segment_material: Material = None,
|
||||
text_material: Material = None,
|
||||
):
|
||||
fraction = math(operation=Math.Operation.DIVIDE, value=(value, total))
|
||||
sweep = math(operation=Math.Operation.MULTIPLY, value=(fraction, TAU))
|
||||
end = math(operation=Math.Operation.ADD, value=(start, sweep))
|
||||
|
||||
percentage = math(operation=Math.Operation.MULTIPLY, value=(fraction, 100.0))
|
||||
percentage_string = value_to_string(data_type=ValueToString.DataType.FLOAT, value=percentage, decimals=2)
|
||||
label = join_strings(delimiter="", strings=[percentage_string, string(string="%")])
|
||||
|
||||
arc_curve = arc(
|
||||
mode=Arc.Mode.RADIUS,
|
||||
resolution=64,
|
||||
radius=1.0,
|
||||
start_angle=start,
|
||||
sweep_angle=sweep,
|
||||
connect_center=True,
|
||||
)
|
||||
face = arc_curve.fill_curve()
|
||||
extruded_face = face.extrude_mesh(mode=ExtrudeMesh.Mode.FACES, offset_scale=-0.1)
|
||||
|
||||
text_curve = string_to_curves(string=label, size=0.2, align_x="Center", align_y="Middle").curve_instances
|
||||
text_face = text_curve.fill_curve()
|
||||
text_mesh = text_face.extrude_mesh(mode=ExtrudeMesh.Mode.FACES, offset_scale=0.025).mesh
|
||||
face_center = attribute_statistic(
|
||||
data_type=AttributeStatistic.DataType.FLOAT_VECTOR,
|
||||
domain=AttributeStatistic.Domain.FACE,
|
||||
geometry=face,
|
||||
attribute=position(),
|
||||
).mean
|
||||
positioned_text = text_mesh.set_position(offset=face_center).set_material(material=text_material)
|
||||
|
||||
mid_angle = math(operation=Math.Operation.ADD, value=(start, math(operation=Math.Operation.DIVIDE, value=(sweep, 2.0))))
|
||||
shift_vector = combine_xyz(
|
||||
x=math(operation=Math.Operation.MULTIPLY, value=(math(operation=Math.Operation.COSINE, value=mid_angle), shift)),
|
||||
y=math(operation=Math.Operation.MULTIPLY, value=(math(operation=Math.Operation.SINE, value=mid_angle), shift)),
|
||||
z=0.0,
|
||||
)
|
||||
|
||||
segment = extruded_face.mesh.set_material(material=segment_material)
|
||||
cap = face.set_material(material=segment_material)
|
||||
geometry = join_geometry(geometry=[positioned_text, segment, cap]).set_position(offset=shift_vector)
|
||||
return {"Curve": geometry, "End": end}
|
||||
|
||||
|
||||
@tree("VG Pie Chart")
|
||||
def vg_pie_chart(
|
||||
geometry: Geometry,
|
||||
a: Float = 0.5,
|
||||
a_shift: Float = 0.5,
|
||||
a_material: Material = None,
|
||||
b: Float = 0.5,
|
||||
b_shift: Float = 0.0,
|
||||
b_material: Material = None,
|
||||
c: Float = 0.5,
|
||||
c_shift: Float = 0.0,
|
||||
c_material: Material = None,
|
||||
text_material: Material = None,
|
||||
):
|
||||
del geometry
|
||||
|
||||
total = math(operation=Math.Operation.ADD, value=(math(operation=Math.Operation.ADD, value=(a, b)), c))
|
||||
a_geometry, a_end = vg_pie_segment(
|
||||
start=0.0,
|
||||
value=a,
|
||||
total=total,
|
||||
shift=a_shift,
|
||||
segment_material=a_material,
|
||||
text_material=text_material,
|
||||
)
|
||||
b_geometry, b_end = vg_pie_segment(
|
||||
start=a_end,
|
||||
value=b,
|
||||
total=total,
|
||||
shift=b_shift,
|
||||
segment_material=b_material,
|
||||
text_material=text_material,
|
||||
)
|
||||
c_geometry, _c_end = vg_pie_segment(
|
||||
start=b_end,
|
||||
value=c,
|
||||
total=total,
|
||||
shift=c_shift,
|
||||
segment_material=c_material,
|
||||
text_material=text_material,
|
||||
)
|
||||
return join_geometry(geometry=[a_geometry, b_geometry, c_geometry])
|
||||
|
||||
|
||||
def _finalize_groups():
|
||||
import bpy
|
||||
|
||||
groups = []
|
||||
for name in ("VG Pie Segment", "VG Pie Chart"):
|
||||
group = bpy.data.node_groups.get(name)
|
||||
if not group:
|
||||
continue
|
||||
group.use_fake_user = True
|
||||
if hasattr(group, "interface"):
|
||||
for item in group.interface.items_tree:
|
||||
if item.item_type == "SOCKET" and item.in_out == "OUTPUT" and item.name == "Result":
|
||||
item.name = "Geometry"
|
||||
if item.item_type == "SOCKET" and item.in_out == "INPUT" and item.name in {"A", "B", "C"}:
|
||||
item.name = item.name.lower()
|
||||
groups.append(group)
|
||||
return groups
|
||||
|
||||
|
||||
_finalize_groups()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
for group in _finalize_groups():
|
||||
print(
|
||||
"VG_PIE_GROUP",
|
||||
group.name,
|
||||
len(group.nodes),
|
||||
len(group.links),
|
||||
sorted(set(node.bl_idname for node in group.nodes)),
|
||||
)
|
||||
|
|
@ -35,6 +35,10 @@ The completed Cartesian function translation is
|
|||
`Geometry Nodes Line`, `Geometry Nodes Parabola`, and `Geometry Nodes Circle`
|
||||
from `cartesian.blend`.
|
||||
|
||||
The completed pie chart translation is
|
||||
`docs/research/translations/shriinivas-piechart.md`. It covers `NodeGroup` and
|
||||
`Pie Chart` from `piechart.blend`.
|
||||
|
||||
`docs/research/procedural-doctrine.md` now stores the current intuitive model
|
||||
for mapping geometric ideas to Geometry Script: curves as rails, fields as
|
||||
weather, `Set Position` as the hinge, profiles as body, attributes as optional
|
||||
|
|
@ -46,8 +50,8 @@ Run `.\tools\setup_geometry_script_clone.ps1` if `external/geometry-script` is
|
|||
missing in a fresh workspace.
|
||||
|
||||
The current next action is to select the next Tier 1 source graph from
|
||||
`Shriinivas/geometrynodes`, preferably `piechart.blend` or `fieldvalue.blend`,
|
||||
inspect its node groups, and add the next doctrine-backed translation entry.
|
||||
`Shriinivas/geometrynodes`, preferably `fieldvalue.blend`, inspect its node
|
||||
groups, and add the next doctrine-backed translation entry.
|
||||
|
||||
## Important Invariants
|
||||
|
||||
|
|
|
|||
|
|
@ -6,3 +6,4 @@
|
|||
{"ts": "2026-05-04T12:24:11+00:00", "type": "verification", "status": "accepted", "note": "Verified translated Shriinivas cartesian helper behavior against source NodeGroup.001 by wrapping both helpers as Curve+Vector -> Set Position -> Curve to Mesh and comparing evaluated mesh vertices. Test used Count=25, Start=(-0.45,0,0), End=(0.45,0,0), r=0.6, Value=1.25; source and translation both produced 200 vertices with max delta 0.0."}
|
||||
{"ts": "2026-05-04T12:42:20+00:00", "type": "implementation", "status": "accepted", "note": "Translated and verified all four inspected Shriinivas/cartesian.blend graph groups: helper, line, parabola, and circle. Verification compares evaluated meshes in Blender 5.1.1; helper/line/parabola match direct vertex order with max delta 0.0, circle matches sorted vertex set with max sorted delta 0.0."}
|
||||
{"ts": "2026-05-04T12:42:20+00:00", "type": "tooling", "status": "accepted", "note": "Reverted direct AppData Geometry Script surgery. Cloned upstream Geometry Script into ignored external/geometry-script, committed local branch vibegeometry/blender-5-nested-tree-groups with nested @tree group fix, stored patch under patches/geometry-script, and added setup_geometry_script_clone.ps1 plus loader so VibeGeometry uses the repo-local patched clone."}
|
||||
{"ts": "2026-05-04T12:48:18+00:00", "type": "implementation", "status": "accepted", "note": "Translated and verified Shriinivas/piechart.blend small graph family: NodeGroup -> VG Pie Segment and Pie Chart -> VG Pie Chart. Segment and chart evaluated mesh comparisons both passed in Blender 5.1.1 with sorted max vertex delta 0.0. Doctrine added: reusable groups can pass invisible scalar state such as End angle alongside visible geometry."}
|
||||
|
|
|
|||
|
|
@ -82,5 +82,5 @@ data_flow:
|
|||
- If state grows faster than understanding, cut it back.
|
||||
|
||||
current_status:
|
||||
summary: VibeGeometry has an initial persistence scaffold plus verified Geometry Script translations for all four inspected Shriinivas/cartesian.blend groups: helper, line, parabola, and circle.
|
||||
next_action: Select the next Tier 1 source graph from Shriinivas/geometrynodes, preferably `piechart.blend` or `fieldvalue.blend`, inspect its node groups, and add the next doctrine-backed translation entry.
|
||||
summary: VibeGeometry has an initial persistence scaffold plus verified Geometry Script translations for the inspected Shriinivas cartesian and pie chart graph families.
|
||||
next_action: Select the next Tier 1 source graph from Shriinivas/geometrynodes, preferably `fieldvalue.blend`, inspect its node groups, and add the next doctrine-backed translation entry.
|
||||
|
|
|
|||
175
tools/verify_piechart_translations.py
Normal file
175
tools/verify_piechart_translations.py
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
"""Compare Shriinivas pie chart source graphs against Geometry Script translations."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import json
|
||||
import math
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
TRANSLATION = ROOT / "examples" / "geometry_script" / "shriinivas_piechart.py"
|
||||
|
||||
|
||||
def _load_translation() -> None:
|
||||
spec = importlib.util.spec_from_file_location("vg_piechart_translation", TRANSLATION)
|
||||
if spec is None or spec.loader is None:
|
||||
raise RuntimeError(f"Could not load translation script: {TRANSLATION}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = module
|
||||
spec.loader.exec_module(module)
|
||||
|
||||
|
||||
def _socket_by_name(sockets: Any, name: str):
|
||||
for socket in sockets:
|
||||
if socket.name == name:
|
||||
return socket
|
||||
raise KeyError(name)
|
||||
|
||||
|
||||
def _new_geometry_group(name: str) -> bpy.types.GeometryNodeTree:
|
||||
if name in bpy.data.node_groups:
|
||||
bpy.data.node_groups.remove(bpy.data.node_groups[name])
|
||||
group = bpy.data.node_groups.new(name, "GeometryNodeTree")
|
||||
group.is_modifier = True
|
||||
group.interface.new_socket(name="Geometry", in_out="INPUT", socket_type="NodeSocketGeometry")
|
||||
group.interface.new_socket(name="Geometry", in_out="OUTPUT", socket_type="NodeSocketGeometry")
|
||||
return group
|
||||
|
||||
|
||||
def _set_inputs(group_node: bpy.types.GeometryNode, values: dict[str, object]) -> None:
|
||||
lower_values = {name.lower(): value for name, value in values.items()}
|
||||
for socket in group_node.inputs:
|
||||
if socket.name in values:
|
||||
socket.default_value = values[socket.name]
|
||||
elif socket.name.lower() in lower_values:
|
||||
socket.default_value = lower_values[socket.name.lower()]
|
||||
|
||||
|
||||
def _build_segment_wrapper(name: str, group: bpy.types.GeometryNodeTree, inputs: dict[str, object]):
|
||||
wrapper = _new_geometry_group(name)
|
||||
nodes = wrapper.nodes
|
||||
links = wrapper.links
|
||||
group_node = nodes.new("GeometryNodeGroup")
|
||||
group_node.node_tree = group
|
||||
_set_inputs(group_node, inputs)
|
||||
group_output = nodes.new("NodeGroupOutput")
|
||||
links.new(_socket_by_name(group_node.outputs, "Curve"), _socket_by_name(group_output.inputs, "Geometry"))
|
||||
return wrapper
|
||||
|
||||
|
||||
def _build_chart_wrapper(name: str, group: bpy.types.GeometryNodeTree, inputs: dict[str, object]):
|
||||
wrapper = _new_geometry_group(name)
|
||||
nodes = wrapper.nodes
|
||||
links = wrapper.links
|
||||
group_input = nodes.new("NodeGroupInput")
|
||||
group_node = nodes.new("GeometryNodeGroup")
|
||||
group_node.node_tree = group
|
||||
_set_inputs(group_node, inputs)
|
||||
group_output = nodes.new("NodeGroupOutput")
|
||||
if any(socket.name == "Geometry" for socket in group_node.inputs):
|
||||
links.new(_socket_by_name(group_input.outputs, "Geometry"), _socket_by_name(group_node.inputs, "Geometry"))
|
||||
links.new(_socket_by_name(group_node.outputs, "Geometry"), _socket_by_name(group_output.inputs, "Geometry"))
|
||||
return wrapper
|
||||
|
||||
|
||||
def _evaluated_vertices(group: bpy.types.GeometryNodeTree) -> list[tuple[float, float, float]]:
|
||||
mesh = bpy.data.meshes.new(group.name + " Input Mesh")
|
||||
obj = bpy.data.objects.new(group.name + " Object", mesh)
|
||||
bpy.context.collection.objects.link(obj)
|
||||
modifier = obj.modifiers.new(group.name + " Modifier", "NODES")
|
||||
modifier.node_group = group
|
||||
depsgraph = bpy.context.evaluated_depsgraph_get()
|
||||
evaluated = obj.evaluated_get(depsgraph)
|
||||
evaluated_mesh = evaluated.to_mesh()
|
||||
try:
|
||||
return [tuple(vertex.co) for vertex in evaluated_mesh.vertices]
|
||||
finally:
|
||||
evaluated.to_mesh_clear()
|
||||
|
||||
|
||||
def _bounds(vertices: list[tuple[float, float, float]]) -> dict[str, list[float]]:
|
||||
return {
|
||||
"min": [min(vertex[i] for vertex in vertices) for i in range(3)],
|
||||
"max": [max(vertex[i] for vertex in vertices) for i in range(3)],
|
||||
}
|
||||
|
||||
|
||||
def _compare(case: str, source_vertices, translated_vertices) -> dict[str, object]:
|
||||
if len(source_vertices) != len(translated_vertices):
|
||||
return {
|
||||
"case": case,
|
||||
"ok": False,
|
||||
"reason": "vertex_count_mismatch",
|
||||
"source_vertex_count": len(source_vertices),
|
||||
"translated_vertex_count": len(translated_vertices),
|
||||
"source_bounds": _bounds(source_vertices) if source_vertices else None,
|
||||
"translated_bounds": _bounds(translated_vertices) if translated_vertices else None,
|
||||
}
|
||||
max_delta = 0.0
|
||||
for source, translated in zip(sorted(source_vertices), sorted(translated_vertices)):
|
||||
max_delta = max(max_delta, math.dist(source, translated))
|
||||
return {
|
||||
"case": case,
|
||||
"ok": max_delta <= 1e-6,
|
||||
"source_vertex_count": len(source_vertices),
|
||||
"translated_vertex_count": len(translated_vertices),
|
||||
"max_sorted_vertex_delta": max_delta,
|
||||
"source_bounds": _bounds(source_vertices),
|
||||
"translated_bounds": _bounds(translated_vertices),
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
_load_translation()
|
||||
text_material = bpy.data.materials.get("Text Material") or bpy.data.materials.new("Text Material")
|
||||
mat1 = bpy.data.materials.get("Material 1") or bpy.data.materials.new("Material 1")
|
||||
mat2 = bpy.data.materials.get("Material 2") or bpy.data.materials.new("Material 2")
|
||||
mat3 = bpy.data.materials.get("Material 3") or bpy.data.materials.new("Material 3")
|
||||
|
||||
segment_inputs = {
|
||||
"Start": 0.35,
|
||||
"Value": 0.8,
|
||||
"Total": 2.4,
|
||||
"Shift": 0.2,
|
||||
"Segment Material": mat1,
|
||||
"Text Material": text_material,
|
||||
}
|
||||
chart_inputs = {
|
||||
"A": 0.8,
|
||||
"A Shift": 0.2,
|
||||
"A Material": mat1,
|
||||
"B": 1.1,
|
||||
"B Shift": 0.05,
|
||||
"B Material": mat2,
|
||||
"C": 0.5,
|
||||
"C Shift": 0.0,
|
||||
"C Material": mat3,
|
||||
"Text Material": text_material,
|
||||
}
|
||||
|
||||
cases = [
|
||||
(
|
||||
"segment",
|
||||
_build_segment_wrapper("VG Verify Source Pie Segment", bpy.data.node_groups["NodeGroup"], segment_inputs),
|
||||
_build_segment_wrapper("VG Verify Translated Pie Segment", bpy.data.node_groups["VG Pie Segment"], segment_inputs),
|
||||
),
|
||||
(
|
||||
"chart",
|
||||
_build_chart_wrapper("VG Verify Source Pie Chart", bpy.data.node_groups["Pie Chart"], chart_inputs),
|
||||
_build_chart_wrapper("VG Verify Translated Pie Chart", bpy.data.node_groups["VG Pie Chart"], chart_inputs),
|
||||
),
|
||||
]
|
||||
results = [_compare(case, _evaluated_vertices(source), _evaluated_vertices(translated)) for case, source, translated in cases]
|
||||
ok = all(result["ok"] for result in results)
|
||||
print("VG_PIECHART_TRANSLATION_BEHAVIOR " + json.dumps({"ok": ok, "results": results}, sort_keys=True))
|
||||
return 0 if ok else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loading…
Reference in a new issue