Closed nerdfever closed 7 years ago
Hmm... there's nothing built in that would deal with this, but I would approach it by adding a @material('Z-ABS')
decorator that would add a material
attribute to each returned value, then run things through a scaling process before finally rendering to OpenSCAD. Here's a quick example.
I haven't tested this much or thought it all the way through. Note that it's only going to scale the top level of a tree, so if you take the union of an ABS
part and a PET
part and apply the ULTRAT
material to that union, the entire piece will be scaled as if it were ULTRAT
. But if you're serious about designing parts for particular materials, you probably wouldn't be mixing parts like that anyway.
So, uh... good luck!
from solid import *
from solid.utils import *
ABS = 'Z-ABS'
ULTRAT = 'Z-ULTRAT'
PET = 'Z-PETG'
MATERIAL_SCALES = {
ABS: [1.0, 1.0, 1.0],
ULTRAT: [1.00413, 0.99732, 1.0],
PET: [1.0, 1.0, 1.0]
}
def material(material_name):
def wrap(f):
def wrapped_f(*args):
val = f(*args)
setattr(val, 'material', material_name)
return val
return wrapped_f
return wrap
@material(ABS)
def abs_part():
# your part logic here...
part = right(3)(
sphere(r=1)
)
return part
@material(ULTRAT)
def ultrat_part():
# your part logic here...
part = left(3)(
cylinder(r=1, h=1)
)
return part
def apply_materials(sp_object):
'''
Recursively look at all solidpython objects in a tree, scaling
any part of a tree that has a 'material' attribute by the appropriate
scale factor.
Note that this stops evaluating objects in the tree once the first `material`
property is found, so you could easily turn one material into another by
unioning/differencing it with a part of a different material.
Lots of room for improvement here.
'''
if hasattr(sp_object, 'material'):
v = MATERIAL_SCALES.get(sp_object.material, [1,1,1])
return scale(v)(sp_object)
elif sp_object.children:
sp_object.children = [apply_materials(c) for c in sp_object.children]
return sp_object
else:
return sp_object
def material_example():
my_objs = union()(abs_part(), ultrat_part(), cube(1, center=True))
return apply_materials(my_objs)
mat_ex = material_example()
print(scad_render(mat_ex))
Wow; that's easier than I hoped. 👍
My printer (like most) can only print one material at a time, so if you did have parts with different materials fitting together in something, you'd need separate .STL files for each material anyway.
I'll play with this and let you know how it goes. May be a week or two (this is a spare-time project).
Makes sense. Although, if you're going to make separate STLs for each, you probably just want to get all your parts of a given material together all at once and then call scale(v=<material_scale_vec>)(parts_list)
on them; don't even worry about the decorator stuff. Good luck!
Why not handle this in the slicer software? It seems to me that the code should be an empirical representation of the object and calibration for actual printing should be done in the print software.
Because I'm not writing the slicer software, but I'm writing the SolidPython code.
Every slicer i've used had a scale x, y and z already built-in so it seems redundant. If yours doesn't, then I guess I understand the request.
Not sure if this is trivial or difficult...
I'm using SolidPython to generate .STL files for 3D printing camera lens adapters, where accuracy matters.
The material shrinks a bit, and worse, the printer prints slightly larger in the X direction than in the Y direction (by a fraction of 1%).
Is there some way to get SolidPython to apply X, Y, and Z correction factors to all positions before generating the OpenSCAD code? I'm thinking of a "shim" layer that takes all the sizes and positions and multiplies them by correction factors, like this:
The idea is that for each material, there is an X, Y, and Z correction factor to be applied.
Any suggestions?