Cannot pass OpenSCADObject as parameter
ebak opened this issue · 3 comments
Hi,
Thanks for creating SolidPython! It is a very useful tool for OpenSCAD.
I have recently started to use its Importing OpenSCAD code feature (https://solidpython.readthedocs.io/en/latest/#importing-openscad-code), and luckily I started with a case which doesn't seem to be supported.
I had problem with the Round-Anything module's polyRound() function: https://kurthutten.com/blog/round-anything-api/
An example OpenSCAD code looks like:
radiiPoints=[[-4,0,1],[5,3,1.5],[0,7,0.1],[8,7,10],[20,20,0.8],[10,0,10]];
polygon(polyRound(radiiPoints,30));
Calling it from SolidPython would look like:
import solid as sd
rounder = sd.import_scad('polyround.scad')
rpoints = [
(-10, -10, 3), (-10, 10, 3), (10, 10, 3), (10, -10, 3)]
pr = rounder.polyRound(radiipoints=rpoints, fn=32) # It is an OpenSCADObject
poly = sd.polygon(points=pr) # OpenSCADObject is passed as parameter
Unfortunately it doesn't work since the constructor of solid.polygon, which cannot take on OpenSCADObject parameters:
def __init__(self, points: Points, paths: Indexes = None) -> None:
if not paths:
paths = [list(range(len(points)))]
super().__init__('polygon',
{'points': _to_point2s(points), 'paths': paths})
It would be very nice to support OpenSCADObjects as paramters.
I have created a very ugly draft patch for myself to make it work:
import solid as sd
import solid.solidpython
from typing import Union, Iterable
from solid.objects import _to_point2s
from solid import OpenSCADObject, Points, Indexes
rounder = sd.import_scad('../SCAD.libs/Round-Anything-master/polyround.scad')
def patched_py2openscad(o: Union[bool, float, str, Iterable]) -> str:
if isinstance(o, OpenSCADObject):
return o._render()[:-1] # PATCH
if type(o) == bool:
return str(o).lower()
if type(o) == float:
return f"{o:.10f}" # type: ignore
if type(o) == str:
return f'\"{o}\"' # type: ignore
if type(o).__name__ == "ndarray":
import numpy # type: ignore
return numpy.array2string(o, separator=",", threshold=1000000000)
if hasattr(o, "__iter__"):
s = "["
first = True
for i in o: # type: ignore
if not first:
s += ", "
first = False
s += patched_py2openscad(i)
s += "]"
return s
return str(o)
class patched_polygon(OpenSCADObject):
def __init__(self, points: Points, paths: Indexes = None) -> None:
if isinstance(points, OpenSCADObject):
super().__init__(
'polygon',
{'points': points})
else:
if not paths:
paths = [list(range(len(points)))]
super().__init__('polygon',
{'points': _to_point2s(points), 'paths': paths})
solid.solidpython.py2openscad = patched_py2openscad # PATCH
sd.polygon = patched_polygon # PATCH
rpoints = [
(-10, -10, 3),
(-10, 10, 3),
(10, 10, 3),
(10, -10, 3)]
pr = rounder.polyRound(radiipoints=rpoints, fn=32) # It is an OpenSCADObject
poly = sd.polygon(points=pr) # OpenSCADObject is passed as parameter
def save(sdobj, fname):
scad = sd.scad_render(sdobj)
with open(fname, "w") as f:
f.write(pr.include_string + '\n') # This is a very ugly workaround!
f.write(scad)
save(poly, 'example.scad')
Would it be possible to implement a nice solution for this use-case?
Best Regards,
Endre
Hi Endre - This issue has come up before, but I think this is a possible way forward that would allow us to use imported OpenSCAD code to make calculations as well as create geometry, which is how I wrote this in the first place.
Thanks for your code here! I think this has promise for dealing with polygon(), and I think we may be able to apply it in a few other parts of the code so that all the functions that could take non-geometry arguments could reasonably accept imported OpenSCAD calculations (instances of IncludedOpenSCADObject). More here soon...
Give the version released on PyPI as SolidPython 1.0.3 a try; it should have resolved this issue. In addition, any SolidPython object should be able to take imported OpenSCAD code as an argument to a function, so this should be a general solution to the problem.
There are, I think some complexities to this approach. If you did a set of nested calculations with imported OpenSCAD code, I'm not certain this would represent them correctly. BUT, for most purposes, which is "Somebody did some calculations I need in this OpenSCAD module-- can I just use them in SolidPython?", this should do the trick.
Hi,
I have verified this with the polygon stuffs. Works great. Thanks!