VibeGeometry/examples/geometry_script/shriinivas_paramnpolareq.py
2026-05-04 16:58:28 +01:00

509 lines
18 KiB
Python

"""Geometry Script recreations from Shriinivas/paramnpolareq.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
def _accumulated_parameter(resolution, max_value):
step = math(
operation=Math.Operation.DIVIDE,
value=(max_value, math(operation=Math.Operation.SUBTRACT, value=(resolution, 1.0))),
)
return accumulate_field(
data_type=AccumulateField.DataType.FLOAT,
domain=AccumulateField.Domain.POINT,
value=step,
).trailing
def _choose_float(curve_type, val0, val1, val2, val3, val4, val5=0.0):
selected = switch(
input_type=Switch.InputType.FLOAT,
switch=compare(
operation=Compare.Operation.EQUAL,
data_type=Compare.DataType.INT,
mode=Compare.Mode.ELEMENT,
a=curve_type,
b=4,
),
false=val5,
true=val4,
)
for index, value in reversed(list(enumerate([val0, val1, val2, val3]))):
selected = switch(
input_type=Switch.InputType.FLOAT,
switch=compare(
operation=Compare.Operation.EQUAL,
data_type=Compare.DataType.INT,
mode=Compare.Mode.ELEMENT,
a=curve_type,
b=index,
),
false=selected,
true=value,
)
return selected
def _choose_string(curve_type, val0, val1, val2, val3, val4, val5=""):
selected = switch(
input_type=Switch.InputType.STRING,
switch=compare(
operation=Compare.Operation.EQUAL,
data_type=Compare.DataType.INT,
mode=Compare.Mode.ELEMENT,
a=curve_type,
b=4,
),
false=val5,
true=val4,
)
for index, value in reversed(list(enumerate([val0, val1, val2, val3]))):
selected = switch(
input_type=Switch.InputType.STRING,
switch=compare(
operation=Compare.Operation.EQUAL,
data_type=Compare.DataType.INT,
mode=Compare.Mode.ELEMENT,
a=curve_type,
b=index,
),
false=selected,
true=value,
)
return selected
@tree("VG Choose Float Val")
def vg_choose_float_val(
curve_type: Int = 0,
val0: Float = 0.0,
val1: Float = 0.0,
val2: Float = 0.0,
val3: Float = 0.0,
val4: Float = 0.0,
val5: Float = 0.0,
):
return {"val": _choose_float(curve_type, val0, val1, val2, val3, val4, val5)}
@tree("VG Choose Str Val")
def vg_choose_str_val(
curve_type: Int = 0,
val0: String = "",
val1: String = "",
val2: String = "",
val3: String = "",
val4: String = "",
val5: String = "",
):
return {"val": _choose_string(curve_type, val0, val1, val2, val3, val4, val5)}
@tree("VG Param Epicycloid X")
def vg_param_epicycloid_x(a: Float = 0.5, b: Float = 0.5, t: Float = 1.0):
ratio_plus_one = math(
operation=Math.Operation.ADD,
value=(math(operation=Math.Operation.DIVIDE, value=(a, b)), 1.0),
)
inner = math(
operation=Math.Operation.MULTIPLY,
value=(b, math(operation=Math.Operation.COSINE, value=math(operation=Math.Operation.MULTIPLY, value=(ratio_plus_one, t)))),
)
outer = math(
operation=Math.Operation.MULTIPLY,
value=(math(operation=Math.Operation.ADD, value=(a, b)), math(operation=Math.Operation.COSINE, value=t)),
)
return {"x": math(operation=Math.Operation.SUBTRACT, value=(outer, inner))}
@tree("VG Param Epicycloid Y")
def vg_param_epicycloid_y(a: Float = 0.5, b: Float = 0.5, t: Float = 1.0):
ratio_plus_one = math(
operation=Math.Operation.ADD,
value=(math(operation=Math.Operation.DIVIDE, value=(a, b)), 1.0),
)
inner = math(
operation=Math.Operation.MULTIPLY,
value=(b, math(operation=Math.Operation.SINE, value=math(operation=Math.Operation.MULTIPLY, value=(ratio_plus_one, t)))),
)
outer = math(
operation=Math.Operation.MULTIPLY,
value=(math(operation=Math.Operation.ADD, value=(a, b)), math(operation=Math.Operation.SINE, value=t)),
)
return {"y": math(operation=Math.Operation.SUBTRACT, value=(outer, inner))}
@tree("VG Polar Spiral X")
def vg_polar_spiral_x(a: Float = 0.5, b: Float = 0.5, theta: Float = 1.0):
radius = math(operation=Math.Operation.ADD, value=(a, math(operation=Math.Operation.MULTIPLY, value=(b, theta))))
return {"x": math(operation=Math.Operation.MULTIPLY, value=(math(operation=Math.Operation.COSINE, value=theta), radius))}
@tree("VG Polar Spiral Y")
def vg_polar_spiral_y(a: Float = 0.5, b: Float = 0.5, theta: Float = 1.0):
radius = math(operation=Math.Operation.ADD, value=(a, math(operation=Math.Operation.MULTIPLY, value=(b, theta))))
return {"y": math(operation=Math.Operation.MULTIPLY, value=(math(operation=Math.Operation.SINE, value=theta), radius))}
@tree("VG Param XY")
def vg_param_xy(a: Float = 0.0, b: Float = 0.0, c: Float = 0.0, t: Float = 0.0, curve_type: Int = 0):
normalized_curve_type = math(
operation=Math.Operation.MODULO,
value=(math(operation=Math.Operation.ABSOLUTE, value=curve_type), 5.0),
)
epi_x = vg_param_epicycloid_x(a=a, b=b, t=t)
epi_y = vg_param_epicycloid_y(a=a, b=b, t=t)
epitrochoid_x = math(
operation=Math.Operation.SUBTRACT,
value=(
math(operation=Math.Operation.MULTIPLY, value=(math(operation=Math.Operation.ADD, value=(a, b)), math(operation=Math.Operation.COSINE, value=t))),
math(
operation=Math.Operation.MULTIPLY,
value=(
c,
math(
operation=Math.Operation.COSINE,
value=math(
operation=Math.Operation.MULTIPLY,
value=(math(operation=Math.Operation.ADD, value=(math(operation=Math.Operation.DIVIDE, value=(a, b)), 1.0)), t),
),
),
),
),
),
)
epitrochoid_y = math(
operation=Math.Operation.SUBTRACT,
value=(
math(operation=Math.Operation.MULTIPLY, value=(math(operation=Math.Operation.ADD, value=(a, b)), math(operation=Math.Operation.SINE, value=t))),
math(
operation=Math.Operation.MULTIPLY,
value=(
c,
math(
operation=Math.Operation.SINE,
value=math(
operation=Math.Operation.MULTIPLY,
value=(math(operation=Math.Operation.ADD, value=(math(operation=Math.Operation.DIVIDE, value=(a, b)), 1.0)), t),
),
),
),
),
),
)
hypo_x = math(
operation=Math.Operation.ADD,
value=(
math(operation=Math.Operation.MULTIPLY, value=(math(operation=Math.Operation.SUBTRACT, value=(a, b)), math(operation=Math.Operation.COSINE, value=t))),
math(
operation=Math.Operation.MULTIPLY,
value=(
b,
math(
operation=Math.Operation.COSINE,
value=math(
operation=Math.Operation.MULTIPLY,
value=(math(operation=Math.Operation.SUBTRACT, value=(math(operation=Math.Operation.DIVIDE, value=(a, b)), 1.0)), t),
),
),
),
),
),
)
hypo_y = math(
operation=Math.Operation.SUBTRACT,
value=(
math(operation=Math.Operation.MULTIPLY, value=(math(operation=Math.Operation.SUBTRACT, value=(a, b)), math(operation=Math.Operation.SINE, value=t))),
math(
operation=Math.Operation.MULTIPLY,
value=(
b,
math(
operation=Math.Operation.SINE,
value=math(
operation=Math.Operation.MULTIPLY,
value=(math(operation=Math.Operation.SUBTRACT, value=(math(operation=Math.Operation.DIVIDE, value=(a, b)), 1.0)), t),
),
),
),
),
),
)
hypotrochoid_x = math(
operation=Math.Operation.ADD,
value=(
math(operation=Math.Operation.MULTIPLY, value=(math(operation=Math.Operation.SUBTRACT, value=(a, b)), math(operation=Math.Operation.COSINE, value=t))),
math(
operation=Math.Operation.MULTIPLY,
value=(
c,
math(
operation=Math.Operation.COSINE,
value=math(
operation=Math.Operation.MULTIPLY,
value=(math(operation=Math.Operation.SUBTRACT, value=(math(operation=Math.Operation.DIVIDE, value=(a, b)), 1.0)), t),
),
),
),
),
),
)
hypotrochoid_y = math(
operation=Math.Operation.SUBTRACT,
value=(
math(operation=Math.Operation.MULTIPLY, value=(math(operation=Math.Operation.SUBTRACT, value=(a, b)), math(operation=Math.Operation.SINE, value=t))),
math(
operation=Math.Operation.MULTIPLY,
value=(
c,
math(
operation=Math.Operation.SINE,
value=math(
operation=Math.Operation.MULTIPLY,
value=(math(operation=Math.Operation.SUBTRACT, value=(math(operation=Math.Operation.DIVIDE, value=(a, b)), 1.0)), t),
),
),
),
),
),
)
arch_radius = math(operation=Math.Operation.ADD, value=(a, math(operation=Math.Operation.MULTIPLY, value=(b, t))))
arch_x = math(operation=Math.Operation.MULTIPLY, value=(arch_radius, math(operation=Math.Operation.COSINE, value=t)))
arch_y = math(operation=Math.Operation.MULTIPLY, value=(arch_radius, math(operation=Math.Operation.SINE, value=t)))
linebreak = special_characters().line_break
eq = _choose_string(
normalized_curve_type,
join_strings(
delimiter=linebreak,
strings=[
string(string="y = ((a + b) * sin(t)) - (b * sin((a/b + 1) * t))"),
string(string="x = ((a + b) * cos(t)) - (b * cos((a/b + 1) * t))"),
string(string="Epicycloid"),
],
),
join_strings(
delimiter=linebreak,
strings=[
string(string="y = ((a + b) * sin(t)) - (c * sin((a/b + 1) * t))"),
string(string="x = ((a + b) * cos(t)) - (c * cos((a/b + 1) * t))"),
string(string="Epitrochoid"),
],
),
join_strings(
delimiter=linebreak,
strings=[
string(string="y = ((a - b) * sin(t)) + (b * sin((a/b - 1) * t))"),
string(string="x = ((a - b) * cos(t)) + (b * cos((a/b - 1) * t))"),
string(string="Hypocycloid"),
],
),
join_strings(
delimiter=linebreak,
strings=[
string(string="y = ((a - b) * sin(t)) + (c * sin((a/b - 1) * t))"),
string(string="x = ((a - b) * cos(t)) + (c * cos((a/b - 1) * t))"),
string(string="Hypotrochoid"),
],
),
join_strings(
delimiter=linebreak,
strings=[
string(string="r = a + b theta"),
string(string="Archimedes Spiral"),
],
),
)
return {
"x": _choose_float(normalized_curve_type, epi_x, epitrochoid_x, hypo_x, hypotrochoid_x, arch_x),
"y": _choose_float(normalized_curve_type, epi_y, epitrochoid_y, hypo_y, hypotrochoid_y, arch_y),
"eq": eq,
}
@tree("VG Archimedes Spiral")
def vg_archimedes_spiral(
resolution: Int = 10,
no_of_rounds: Float = 0.5,
a: Float = 0.5,
b: Float = 0.5,
):
mesh = mesh_line(
mode=MeshLine.Mode.OFFSET,
count_mode=MeshLine.CountMode.TOTAL,
count=resolution,
start_location=(0.0, 0.0, 0.0),
offset=(0.0, 0.0, 1.0),
)
theta = _accumulated_parameter(
resolution=resolution,
max_value=math(operation=Math.Operation.MULTIPLY, value=(no_of_rounds, TAU)),
)
positioned = mesh.set_position(
position=combine_xyz(
x=vg_polar_spiral_x(a=a, b=b, theta=theta),
y=vg_polar_spiral_y(a=a, b=b, theta=theta),
z=0.0,
)
)
return {"Geometry": positioned}
@tree("VG Epicycloid")
def vg_epicycloid(
resolution: Int = 10,
max_t: Float = 0.5,
a: Float = 0.5,
b: Float = 0.5,
):
mesh = mesh_line(
mode=MeshLine.Mode.OFFSET,
count_mode=MeshLine.CountMode.TOTAL,
count=resolution,
start_location=(0.0, 0.0, 0.0),
offset=(0.0, 0.0, 1.0),
)
t = _accumulated_parameter(resolution=resolution, max_value=max_t)
positioned = mesh.set_position(
position=combine_xyz(
x=vg_param_epicycloid_x(a=a, b=b, t=t),
y=vg_param_epicycloid_y(a=a, b=b, t=t),
z=0.0,
)
)
return {"Geometry": positioned}
@tree("VG Mirrored Root Spiral")
def vg_mirrored_root_spiral(a: Float = 0.30000001192092896, round_count: Float = 5.0, resolution: Float = 500.0):
mesh = mesh_line(
mode=MeshLine.Mode.OFFSET,
count_mode=MeshLine.CountMode.TOTAL,
count=resolution,
start_location=(0.0, 0.0, 0.0),
offset=(0.0, 0.0, 1.0),
)
theta = _accumulated_parameter(
resolution=resolution,
max_value=math(operation=Math.Operation.MULTIPLY, value=(math(operation=Math.Operation.MULTIPLY, value=(round_count, 3.1415927410125732)), 2.0)),
)
radius = math(operation=Math.Operation.MULTIPLY, value=(a, math(operation=Math.Operation.POWER, value=(theta, 0.5))))
x = math(operation=Math.Operation.MULTIPLY, value=(radius, math(operation=Math.Operation.COSINE, value=theta)))
y = math(operation=Math.Operation.MULTIPLY, value=(radius, math(operation=Math.Operation.SINE, value=theta)))
forward = mesh.set_position(position=combine_xyz(x=x, y=y, z=0.0))
mirrored = mesh.set_position(
position=combine_xyz(
x=math(operation=Math.Operation.MULTIPLY, value=(-1.0, x)),
y=math(operation=Math.Operation.MULTIPLY, value=(-1.0, y)),
z=0.0,
)
)
return {"Geometry": join_geometry(geometry=[mirrored, forward])}
def _empty_curve_geometry():
return mesh_line(
mode=MeshLine.Mode.OFFSET,
count_mode=MeshLine.CountMode.TOTAL,
count=0,
offset=(0.0, 0.0, 1.0),
)
@tree("VG Param Curve")
def vg_param_curve(
curve_type: Int = 0,
a: Float = 0.800000011920929,
b: Float = 0.5,
c: Float = 1.0,
z: Float = 0.0,
max_t: Float = 32.5,
resolution: Float = 500.0,
showlabel: Bool = True,
thickness: Float = 0.009999999776482582,
curve_material: Material = None,
text_material: Material = None,
):
t = _accumulated_parameter(resolution=resolution, max_value=max_t)
x, y, equation = vg_param_xy(a=a, b=b, c=c, t=t, curve_type=curve_type)
text_curve = string_to_curves(
string=equation,
size=2.0,
align_x="Center",
align_y="Middle",
pivot_point="Bottom Left",
).curve_instances
label = transform_geometry(
geometry=fill_curve(curve=text_curve, mode="Triangles", fill_rule="Even-Odd").set_material(material=text_material),
translation=(0.0, 0.0, 0.30000001192092896),
)
label_or_empty = switch(input_type=Switch.InputType.GEOMETRY, switch=showlabel, false=_empty_curve_geometry(), true=label)
rail_seed = mesh_line(
mode=MeshLine.Mode.OFFSET,
count_mode=MeshLine.CountMode.TOTAL,
count=resolution,
start_location=(0.0, 0.0, 0.0),
offset=(0.0, 0.0, 1.0),
)
rail = mesh_to_curve(mode=MeshToCurve.Mode.EDGES, mesh=rail_seed).set_position(position=combine_xyz(x=x, y=y, z=z))
profile = curve_circle(mode=CurveCircle.Mode.RADIUS, resolution=32, radius=thickness)
radius_attribute = named_attribute(data_type=NamedAttribute.DataType.FLOAT, name="radius")
radius_scale = switch(input_type=Switch.InputType.FLOAT, switch=radius_attribute.exists, false=1.0, true=radius_attribute.attribute)
curve_mesh = rail.curve_to_mesh(profile_curve=profile, scale=radius_scale, fill_caps=False).set_material(material=curve_material)
return {"Geometry": join_geometry(geometry=[label_or_empty, curve_mesh])}
def _finalize_groups():
import bpy
groups = []
for name in (
"VG Param Epicycloid X",
"VG Param Epicycloid Y",
"VG Polar Spiral X",
"VG Polar Spiral Y",
"VG Choose Float Val",
"VG Choose Str Val",
"VG Param XY",
"VG Archimedes Spiral",
"VG Epicycloid",
"VG Mirrored Root Spiral",
"VG Param Curve",
):
group = bpy.data.node_groups.get(name)
if group:
group.use_fake_user = True
groups.append(group)
return groups
_finalize_groups()
if __name__ == "__main__":
for group in _finalize_groups():
print(
"VG_PARAMNPOLAREQ_GROUP",
group.name,
len(group.nodes),
len(group.links),
sorted(set(node.bl_idname for node in group.nodes)),
)