Skip to content

Commit 0017618

Browse files
Merge branch 'develop'
2 parents de954d7 + 9190617 commit 0017618

File tree

5 files changed

+238
-88
lines changed

5 files changed

+238
-88
lines changed

solid/examples/scad_to_include.scad

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
external_var = false;
12
module steps( howmany=3){
23
union(){
34
for (i=[0:howmany-1]){
@@ -6,4 +7,10 @@ module steps( howmany=3){
67
}
78
}
89
}
10+
11+
if ( external_var){
12+
echo( "external_var passed in as true");
13+
}
914
}
15+
16+
echo("This text should appear only when called with include(), not use()");

solid/solidpython.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,10 @@ def use( scad_file_path, use_not_include=True):
145145

146146
for sd in symbols_dicts:
147147
class_str = new_openscad_class_str( sd['name'], sd['args'], sd['kwargs'], scad_file_path, use_not_include)
148-
exec class_str in calling_module().__dict__
148+
# If this is called from 'include', we have to look deeper in the stack
149+
# to find the right module to add the new class to.
150+
stack_depth = 2 if use_not_include else 3
151+
exec class_str in calling_module( stack_depth).__dict__
149152

150153
return True
151154

@@ -566,14 +569,18 @@ class included_openscad_object( openscad_object):
566569
represents imported scad code, so each instance needs to store the path
567570
to the scad file it's included from.
568571
'''
569-
def __init__( self, name, params, include_file_path, use_not_include=False):
572+
def __init__( self, name, params, include_file_path, use_not_include=False, **kwargs):
570573
self.include_file_path = self._get_include_path( include_file_path)
571-
574+
572575
if use_not_include:
573576
self.include_string = 'use <%s>\n'%self.include_file_path
574577
else:
575578
self.include_string = 'include <%s>\n'%self.include_file_path
576579

580+
# Just pass any extra arguments straight on to OpenSCAD; it'll accept them
581+
if kwargs:
582+
params.update( kwargs)
583+
577584
openscad_object.__init__( self, name, params)
578585

579586
def _get_include_path( self, include_file_path):
@@ -623,20 +630,23 @@ def new_openscad_class_str( class_name, args=[], kwargs=[], include_file_path=No
623630
for kwarg in kwargs:
624631
args_str += ', %(kwarg)s=None'%vars()
625632
args_pairs += "'%(kwarg)s':%(kwarg)s, "%vars()
626-
633+
627634
if include_file_path:
628-
result = ("class %(class_name)s( included_openscad_object):\n"
629-
" def __init__(self%(args_str)s):\n"
630-
" included_openscad_object.__init__(self, '%(class_name)s', {%(args_pairs)s }, include_file_path='%(include_file_path)s', use_not_include=%(use_not_include)s )\n"
635+
# NOTE the explicit import of 'solid' below. This is a fix for:
636+
# https://github.com/SolidCode/SolidPython/issues/20 -ETJ 16 Jan 2014
637+
result = ("import solid\n"
638+
"class %(class_name)s( solid.included_openscad_object):\n"
639+
" def __init__(self%(args_str)s, **kwargs):\n"
640+
" solid.included_openscad_object.__init__(self, '%(class_name)s', {%(args_pairs)s }, include_file_path='%(include_file_path)s', use_not_include=%(use_not_include)s, **kwargs )\n"
631641
" \n"
632642
"\n"%vars())
633643
else:
634-
result = ('class %(class_name)s( openscad_object):\n'
644+
result = ("class %(class_name)s( openscad_object):\n"
635645
" def __init__(self%(args_str)s):\n"
636646
" openscad_object.__init__(self, '%(class_name)s', {%(args_pairs)s })\n"
637647
" \n"
638648
"\n"%vars())
639-
649+
640650
return result
641651

642652
def py2openscad(o):

solid/test/test_solidpython.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,36 @@ def test_parse_scad_callables( self):
7474
expected = [{'args': [], 'name': 'hex', 'kwargs': ['width', 'height', 'flats', 'center']}, {'args': [], 'name': 'righty', 'kwargs': ['angle']}, {'args': ['avar'], 'name': 'lefty', 'kwargs': []}, {'args': [], 'name': 'more', 'kwargs': ['a']}, {'args': [], 'name': 'pyramid', 'kwargs': ['side', 'height', 'square', 'centerHorizontal', 'centerVertical']}, {'args': [], 'name': 'no_comments', 'kwargs': ['arg', 'other_arg', 'last_arg']}, {'args': [], 'name': 'float_arg', 'kwargs': ['arg']}]
7575
actual = parse_scad_callables( test_str)
7676
self.assertEqual( expected, actual)
77+
78+
def test_use( self):
79+
include_file = "../examples/scad_to_include.scad"
80+
use( include_file)
81+
a = steps(3)
82+
actual = scad_render( a)
83+
84+
abs_path = a._get_include_path( include_file)
85+
expected = "use <%s>\n\n\nsteps(howmany = 3);"%abs_path
86+
self.assertEqual( expected, actual)
87+
88+
def test_include( self):
89+
include_file = "../examples/scad_to_include.scad"
90+
include( include_file)
91+
a = steps(3)
92+
93+
actual = scad_render( a)
94+
abs_path = a._get_include_path( include_file)
95+
expected = "include <%s>\n\n\nsteps(howmany = 3);"%abs_path
96+
self.assertEqual( expected, actual)
97+
98+
def test_extra_args_to_included_scad( self):
99+
include_file = "../examples/scad_to_include.scad"
100+
use( include_file)
101+
a = steps( 3, external_var=True)
102+
actual = scad_render( a)
103+
104+
abs_path = a._get_include_path( include_file)
105+
expected = "use <%s>\n\n\nsteps(howmany = 3, external_var = true);"%abs_path
106+
self.assertEqual( expected, actual)
77107

78108
def test_background( self):
79109
a = cube(10)

solid/test/test_utils.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,22 +52,28 @@
5252
class TestSPUtils( unittest.TestCase):
5353
# Test cases will be dynamically added to this instance
5454
# using the test case arrays above
55-
def test_split_body_horizontal( self):
56-
body = sphere( 20)
57-
actual_tuple = split_body_horizontal( body, plane_z=10, dowel_holes=True)
58-
actual = [scad_render( b) for b in actual_tuple]
59-
expected = ['\n\ndifference() {\n\tintersection() {\n\t\tsphere(r = 20);\n\t\ttranslate(v = [0, 0, -49990]) {\n\t\t\tcube(center = true, size = 100000);\n\t\t}\n\t}\n\tunion() {\n\t\ttranslate(v = [9.0000000000, 0, 10]) {\n\t\t\tcylinder(h = 30, r = 4.5000000000, center = true);\n\t\t}\n\t\ttranslate(v = [-9.0000000000, 0, 10]) {\n\t\t\tcylinder(h = 30, r = 4.5000000000, center = true);\n\t\t}\n\t}\n}',
60-
'\n\ndifference() {\n\tintersection() {\n\t\tsphere(r = 20);\n\t\ttranslate(v = [0, 0, 50010]) {\n\t\t\tcube(center = true, size = 100000);\n\t\t}\n\t}\n\tunion() {\n\t\ttranslate(v = [9.0000000000, 0, 10]) {\n\t\t\tcylinder(h = 30, r = 4.5000000000, center = true);\n\t\t}\n\t\ttranslate(v = [-9.0000000000, 0, 10]) {\n\t\t\tcylinder(h = 30, r = 4.5000000000, center = true);\n\t\t}\n\t}\n}']
55+
56+
def test_split_body_planar(self):
57+
offset = [10, 10, 10]
58+
body = translate( offset)( sphere( 20))
59+
body_bb = BoundingBox( [40, 40, 40], offset)
60+
actual = []
61+
for split_dir in [ RIGHT_VEC, FORWARD_VEC, UP_VEC]:
62+
actual_tuple = split_body_planar( body, body_bb, cutting_plane_normal=split_dir, cut_proportion=0.25)
63+
actual.append( actual_tuple)
64+
65+
# Ignore the bounding box object that come back, taking only the SCAD objects
66+
actual = [scad_render( a) for splits in actual for a in splits[::2] ]
67+
68+
expected = ['\n\nintersection() {\n\ttranslate(v = [10, 10, 10]) {\n\t\tsphere(r = 20);\n\t}\n\ttranslate(v = [-5.0000000000, 10, 10]) {\n\t\tcube(center = true, size = [10.0000000000, 40, 40]);\n\t}\n}',
69+
'\n\nintersection() {\n\ttranslate(v = [10, 10, 10]) {\n\t\tsphere(r = 20);\n\t}\n\ttranslate(v = [15.0000000000, 10, 10]) {\n\t\tcube(center = true, size = [30.0000000000, 40, 40]);\n\t}\n}',
70+
'\n\nintersection() {\n\ttranslate(v = [10, 10, 10]) {\n\t\tsphere(r = 20);\n\t}\n\ttranslate(v = [10, -5.0000000000, 10]) {\n\t\tcube(center = true, size = [40, 10.0000000000, 40]);\n\t}\n}',
71+
'\n\nintersection() {\n\ttranslate(v = [10, 10, 10]) {\n\t\tsphere(r = 20);\n\t}\n\ttranslate(v = [10, 15.0000000000, 10]) {\n\t\tcube(center = true, size = [40, 30.0000000000, 40]);\n\t}\n}',
72+
'\n\nintersection() {\n\ttranslate(v = [10, 10, 10]) {\n\t\tsphere(r = 20);\n\t}\n\ttranslate(v = [10, 10, -5.0000000000]) {\n\t\tcube(center = true, size = [40, 40, 10.0000000000]);\n\t}\n}',
73+
'\n\nintersection() {\n\ttranslate(v = [10, 10, 10]) {\n\t\tsphere(r = 20);\n\t}\n\ttranslate(v = [10, 10, 15.0000000000]) {\n\t\tcube(center = true, size = [40, 40, 30.0000000000]);\n\t}\n}'
74+
]
6175
self.assertEqual( actual, expected)
62-
63-
def test_split_body_vertical( self):
64-
body = sphere( 20)
65-
actual_tuple = split_body_vertical( body, plane_x=10, dowel_holes=True)
66-
actual = [scad_render( b) for b in actual_tuple]
67-
expected = ['\n\ndifference() {\n\tintersection() {\n\t\tsphere(r = 20);\n\t\ttranslate(v = [-49990, 0, 0]) {\n\t\t\tcube(center = true, size = 100000);\n\t\t}\n\t}\n\tunion() {\n\t\ttranslate(v = [10, 9.0000000000, 0]) {\n\t\t\trotate(a = 90, v = [0, 1, 0]) {\n\t\t\t\tcylinder(h = 30, r = 4.5000000000, center = true);\n\t\t\t}\n\t\t}\n\t\ttranslate(v = [10, -9.0000000000, 0]) {\n\t\t\trotate(a = 90, v = [0, 1, 0]) {\n\t\t\t\tcylinder(h = 30, r = 4.5000000000, center = true);\n\t\t\t}\n\t\t}\n\t}\n}',
68-
'\n\ndifference() {\n\tintersection() {\n\t\tsphere(r = 20);\n\t\ttranslate(v = [50010, 0, 0]) {\n\t\t\tcube(center = true, size = 100000);\n\t\t}\n\t}\n\tunion() {\n\t\ttranslate(v = [10, 9.0000000000, 0]) {\n\t\t\trotate(a = 90, v = [0, 1, 0]) {\n\t\t\t\tcylinder(h = 30, r = 4.5000000000, center = true);\n\t\t\t}\n\t\t}\n\t\ttranslate(v = [10, -9.0000000000, 0]) {\n\t\t\trotate(a = 90, v = [0, 1, 0]) {\n\t\t\t\tcylinder(h = 30, r = 4.5000000000, center = true);\n\t\t\t}\n\t\t}\n\t}\n}']
69-
self.assertEqual( actual, expected)
70-
76+
7177
def test_fillet_2d_add( self):
7278
pts = [ [0,5], [5,5], [5,0], [10,0], [10,10], [0,10],]
7379
p = polygon( pts)

0 commit comments

Comments
 (0)