I needed to quickly match and distribute certain parameters (manually) - in case anyone needs this.
MatchParams — MatchProperties for VisualARQ Document Parameters (Python)
I needed a quick way to copy Document Parameter values from one object to others — like MatchProperties, but for custom VA parameters. Since neither Rhino’s MatchProperties nor any built-in VA tool supports this, I wrote a script.
Key finding: Document Parameters (Rhino Options > Parameters) are managed by VisualARQ, not by Rhino’s UserText system. They are not accessible via rs.GetUserText/rs.SetUserText or RhinoCommon UserStrings. The correct API is VisualARQ.Script with GetAllDocumentParameterIds(), GetParameterValue(), and SetParameterValue().
The script has three modes:
-
Match (m): Pick a source object, select targets — all parameter values are copied. Values are stored in session memory.
-
Repeat (r): Apply the stored values to a new selection without picking a source again.
-
Show (s): Inspect parameter values of a picked object.
Works with any geometry type, no hardcoded parameter names — it reads whatever Document Parameters are defined in the document.
# -*- coding: utf-8 -*-
"""
MatchParams (MP)
Copy VisualARQ Document Parameter values from source to target objects.
Uses VisualARQ.Script API (GetParameterValue / SetParameterValue).
Modes:
m = Match from source object
r = Repeat last parameter set
s = Show parameters of picked object
Alias: MP
"""
import rhinoscriptsyntax as rs
import scriptcontext as sc
import System
import clr
STICKY_PARAMS = "MP_LastParams" # {param_name: value}
# --- VA Setup ---
def load_va():
try:
clr.AddReference("VisualARQ.Script")
except:
pass
try:
import VisualARQ.Script as va
return va
except:
print("ERROR: VisualARQ.Script not available.")
print("Run any VA command first (e.g. vaAbout), then retry.")
return None
def get_doc_params(va):
"""Get all document parameter IDs and names."""
param_ids = va.GetAllDocumentParameterIds()
if not param_ids:
return []
params = []
for pid in param_ids:
name = va.GetParameterName(pid)
params.append((pid, name))
return params
# --- Core Functions ---
def read_params(va, obj_id, params):
"""Read all document parameter values from an object."""
guid = System.Guid(str(obj_id))
result = {}
for pid, name in params:
try:
val = va.GetParameterValue(pid, guid)
result[name] = (pid, val)
except:
result[name] = (pid, None)
return result
def write_params(va, obj_id, param_values):
"""Write parameter values to an object. param_values: {name: (pid, val)}"""
guid = System.Guid(str(obj_id))
ok = 0
for name, (pid, val) in param_values.items():
try:
va.SetParameterValue(pid, guid, val)
ok += 1
except Exception as e:
print(" WARN: {} -> {}".format(name, e))
return ok
def show_params(va, obj_id, params, label="Object"):
"""Print parameter values for an object."""
data = read_params(va, obj_id, params)
has_values = False
print("--- {} Parameters ---".format(label))
for name in sorted(data.keys()):
pid, val = data[name]
display = val if val is not None else "(empty)"
print(" {} = {}".format(name, display))
if val is not None and str(val).strip():
has_values = True
print("")
return data, has_values
# --- Modes ---
def mode_match(va, params):
"""Pick source, read params, pick targets, write params."""
source = rs.GetObject("Pick SOURCE object (with parameter values)", preselect=False)
if not source:
return
data, has_values = show_params(va, source, params, "Source")
if not has_values:
print("Source has no parameter values set.")
return
# Filter to only params that have values
valid = {k: v for k, v in data.items() if v[1] is not None and str(v[1]).strip()}
# Store for repeat
sc.sticky[STICKY_PARAMS] = valid
targets = rs.GetObjects("Select TARGET objects")
if not targets:
return
apply_to_targets(va, targets, valid)
def mode_repeat(va, params):
"""Apply last stored parameter set to new targets."""
if STICKY_PARAMS not in sc.sticky or not sc.sticky[STICKY_PARAMS]:
print("No stored parameters. Run Match (m) first.")
return
valid = sc.sticky[STICKY_PARAMS]
print("--- Stored Parameters ---")
for name in sorted(valid.keys()):
pid, val = valid[name]
print(" {} = {}".format(name, val))
print("")
targets = rs.GetObjects("Select TARGET objects for repeat")
if not targets:
return
apply_to_targets(va, targets, valid)
def mode_show(va, params):
"""Show parameters of picked object."""
obj = rs.GetObject("Pick object to inspect", preselect=True)
if not obj:
return
show_params(va, obj, params, "Inspected")
def apply_to_targets(va, targets, valid):
"""Apply parameter values to target objects."""
count = 0
for t in targets:
n = write_params(va, t, valid)
if n > 0:
count += 1
print(">> {} parameter(s) applied to {} object(s):".format(len(valid), count))
for name in sorted(valid.keys()):
pid, val = valid[name]
print(" {} = {}".format(name, val))
# --- Main ---
def main():
va = load_va()
if not va:
return
params = get_doc_params(va)
if not params:
print("No Document Parameters defined.")
print("Create them in Rhino Options > Parameters first.")
return
print("Document Parameters: {}".format(
", ".join(name for _, name in params)
))
stored = sc.sticky.get(STICKY_PARAMS, {})
info = " [{} stored]".format(len(stored)) if stored else ""
mode = rs.GetString(
"Mode: m=Match, r=Repeat{}, s=Show".format(info),
"m"
)
if not mode:
return
mode = mode.strip().lower()
if mode == "m":
mode_match(va, params)
elif mode == "r":
mode_repeat(va, params)
elif mode == "s":
mode_show(va, params)
else:
print("Unknown mode '{}'. Use m, r, or s.".format(mode))
if __name__ == "__main__":
main()
PS: I let the AI write the text… I am lazy