I do have this basic script and I do want if possible to get the cells from the Material
column to have the same color as the color of the layer on which each object is on. It is possible to achieve this? This script needs to work on both Rhino v7 for MacOS and Windows.
#!/usr/bin/env ironpython2.7
# -*- coding: utf8 -*-
# SimpleCutlist.py
import Rhino
import Rhino.Geometry as g
import rhinoscriptsyntax as rs
import Eto.Drawing as drawing
import Eto.Forms as forms
import scriptcontext
# List of layers to exclude
EXCLUDED_LAYERS = ["Booleans", "Dim", "Default", "Walls"]
# Attributes for the cutlist
class attr:
def __init__(self, name, isEditable, valType):
self.name = name
self.isEditable = isEditable
self.valType = valType
ATTRS = (
attr("_N", True, str), # N (number)
attr("_Name", True, str), # Name
attr("Length", True, float), # Length
attr("Width", True, float), # Width
attr("Thickness", True, float), # Thickness
attr("Material", True, str), # Material
)
def computeDims(obj):
objRef = Rhino.DocObjects.ObjRef(obj)
brep = objRef.Geometry()
edges = list(brep.Edges)
edges.sort(key=lambda edge: edge.GetLength(), reverse=True)
edge = edges[0]
origin = edge.PointAtStart
xPoint = edge.PointAtEnd
xVec = Rhino.Geometry.Vector3d(xPoint - origin)
xVec.Unitize()
face = brep.Faces[0]
yVec = Rhino.Geometry.Vector3d.CrossProduct(face.NormalAt(0, 0), xVec)
yVec.Unitize()
plane = Rhino.Geometry.Plane(origin, xVec, yVec)
verts = list(brep.Vertices)
tMatrix = g.Transform.ChangeBasis(g.Plane.WorldXY, plane)
map(lambda vert: vert.Transform(tMatrix), verts)
verts = list(map(lambda vert: vert.Location, verts))
verts.sort(key=lambda vert: vert.X)
length = verts[-1].X - verts[0].X
verts.sort(key=lambda vert: vert.Y)
width = verts[-1].Y - verts[0].Y
verts.sort(key=lambda vert: vert.Z)
thickness = verts[-1].Z - verts[0].Z
return [length, width, thickness]
class Detail:
def __init__(self, obj):
self.obj = obj
self.id = obj
for attr_obj in ATTRS:
key = attr_obj.name
val = rs.GetUserText(str(obj), key)
if val is None:
default = "0" if attr_obj.valType in [float, str] and key != "Material" else ""
setattr(self, key, default)
rs.SetUserText(str(obj), key, default)
else:
setattr(self, key, val)
self.setDims()
self.update_material_from_layer()
def setDims(self):
dims = computeDims(self.obj)
self.Length = str(round(dims[0], 2))
self.Width = str(round(dims[1], 2))
self.Thickness = str(round(dims[2], 2))
rs.SetUserText(str(self.id), "Length", self.Length)
rs.SetUserText(str(self.id), "Width", self.Width)
rs.SetUserText(str(self.id), "Thickness", self.Thickness)
def update_material_from_layer(self):
objRef = Rhino.DocObjects.ObjRef(self.id)
index = objRef.Object().Attributes.LayerIndex
layer = scriptcontext.doc.Layers[index]
self.Material = layer.Name
self.layer_color = drawing.Color.FromArgb(layer.Color.ToArgb())
rs.SetUserText(str(self.id), "Material", self.Material)
def getParams(self):
return [getattr(self, attr.name) for attr in ATTRS]
def refresh(self):
for attr in ATTRS:
rs.SetUserText(str(self.id), attr.name, getattr(self, attr.name))
class Specification:
def __init__(self, details):
self.details = []
idSet = set(range(len(details)))
self.table = []
while idSet:
curId = idSet.pop()
curDet = details[curId]
curDetails = [curDet]
for id in list(idSet):
if curDet.getParams() == details[id].getParams():
curDetails.append(details[id])
idSet.remove(id)
self.details.append(curDetails)
self.table.append(curDet.getParams())
class SimpleCutlistDialog(forms.Dialog[bool]):
def __init__(self):
self.Title = "Simple Cutlist"
self.Padding = drawing.Padding(2)
self.Resizable = True
self.m_gridview = forms.GridView()
self.m_gridview.ShowHeader = True
for i, attr in enumerate(ATTRS):
column = forms.GridColumn()
column.HeaderText = attr.name if attr.name[0] != "_" else attr.name[1:]
column.Editable = attr.isEditable
column.DataCell = forms.TextBoxCell(i)
self.m_gridview.Columns.Add(column)
self.button = forms.Button(Text="Export CSV")
self.button.Width = 80 # Set a smaller, specific width
self.button.Click += self.buttonClick
layout = forms.DynamicLayout()
layout.AddRow(self.m_gridview)
layout.AddRow(self.button)
self.Content = layout
self.ClientSize = drawing.Size(600, 130)
def buttonClick(self, sender, e):
data = [[col.HeaderText for col in self.m_gridview.Columns]]
data.extend(self.spec.table)
filename = rs.SaveFileName("Save cutlist as", "CSV File (*.csv)|*.csv||")
if filename:
with open(filename, 'w') as f:
for row in data:
f.write("|".join(str(item) for item in row) + "\n")
def setData(self, spec):
self.spec = spec
self.m_gridview.DataStore = spec.table
def main():
objs = rs.GetObjects("Select polysurface objects", 16, preselect=True)
if not objs:
return
filtered_objs = [obj for obj in objs if rs.ObjectLayer(obj) not in EXCLUDED_LAYERS]
if not filtered_objs:
rs.MessageBox("No valid objects found.")
return
details = [Detail(obj) for obj in filtered_objs]
spec = Specification(details)
dialog = SimpleCutlistDialog()
dialog.setData(spec)
Rhino.UI.EtoExtensions.ShowSemiModal(dialog, Rhino.RhinoDoc.ActiveDoc, Rhino.UI.RhinoEtoApp.MainWindow)
if __name__ == "__main__":
main()
Simple_Cutlist.py (5.9 KB)
CL_Material_Color.3dm (447.6 KB)