diff --git a/README.md b/README.md
index f58d7eeb..6232d2fd 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ This Python code:
cube(10),
sphere(15)
)
- print(scad_render( d))
+ print(scad_render(d))
Generates this OpenSCAD code:
@@ -49,7 +49,7 @@ Generates this OpenSCAD code:
That doesn't seem like such a savings, but the following SolidPython code is a
lot shorter (and I think a lot clearer) than the SCAD code it compiles to:
- d = cube( 5) + right(5)( sphere(5)) - cylinder( r=2, h=6)
+ d = cube(5) + right(5)(sphere(5)) - cylinder(r=2, h=6)
Generates this OpenSCAD code:
@@ -57,10 +57,10 @@ Generates this OpenSCAD code:
union(){
cube(5);
translate( [5, 0,0]){
- sphere( 5);
+ sphere(5);
}
}
- cylinder( r=2, h=6);
+ cylinder(r=2, h=6);
}
# Advantages
@@ -79,9 +79,9 @@ impossible in pure OpenSCAD. Among these are:
(You may need to use `sudo pip install solidpython`, depending on your environment.)
-* **OR:** Download SolidPython ( Click [here](https://github.com/SolidCode/SolidPython/archive/master.zip) to download directly, or use git to pull it all down)
+* **OR:** Download SolidPython (Click [here](https://github.com/SolidCode/SolidPython/archive/master.zip) to download directly, or use git to pull it all down)
- ( Note that SolidPython also depends on the [PyEuclid](http://pypi.python.org/pypi/euclid) Vector math library, installable via `sudo pip install euclid`)
+ (Note that SolidPython also depends on the [PyEuclid](http://pypi.python.org/pypi/euclid) Vector math library, installable via `sudo pip install euclid`)
* Unzip the file, probably in ~/Downloads/SolidPython-master
* In a terminal, cd to location of file:
@@ -115,8 +115,8 @@ impossible in pure OpenSCAD. Among these are:
sphere(15)
)
-* Call ```scad_render( py_scad_obj)``` to generate SCAD code. This returns a string of valid OpenSCAD code.
-* *or*: call ```scad_render_to_file( py_scad_obj, filepath)``` to
+* Call ```scad_render(py_scad_obj)``` to generate SCAD code. This returns a string of valid OpenSCAD code.
+* *or*: call ```scad_render_to_file(py_scad_obj, filepath)``` to
store that code in a file.
* If 'filepath' is open in the OpenSCAD IDE and Design =>
'Automatic Reload and Compile' is checked (in the OpenSCAD IDE), calling
@@ -130,7 +130,7 @@ The best way to learn how SolidPython works is to look at the included example c
If you've installed SolidPython, the following line of Python will print(the location of )
the examples directory:
- import os, solid; print(os.path.dirname( solid.__file__) + '/examples')
+ import os, solid; print(os.path.dirname(solid.__file__) + '/examples')
Or browse the example code on Github [here](https://github.com/SolidCode/SolidPython/tree/master/solid/examples)
@@ -142,24 +142,24 @@ Following Elmo Mäntynen's suggestion, SCAD objects override
the basic operators + (union), - (difference), and * (intersection).
So
- c = cylinder( r=10, h=5) + cylinder( r=2, h=30)
+ c = cylinder(r=10, h=5) + cylinder(r=2, h=30)
is the same as:
c = union()(
- cylinder( r=10, h=5),
- cylinder( r=2, h=30)
+ cylinder(r=10, h=5),
+ cylinder(r=2, h=30)
)
Likewise:
- c = cylinder( r=10, h=5)
- c -= cylinder( r=2, h=30)
+ c = cylinder(r=10, h=5)
+ c -= cylinder(r=2, h=30)
is the same as:
c = difference()(
- cylinder( r=10, h=5),
- cylinder( r=2, h=30)
+ cylinder(r=10, h=5),
+ cylinder(r=2, h=30)
)
### First-class Negative Space (Holes)
@@ -215,18 +215,18 @@ My apologies.
### Arcs
I've found this useful for fillets and rounds.
- arc( rad=10, start_degrees=90, end_degrees=210)
+ arc(rad=10, start_degrees=90, end_degrees=210)
draws an arc of radius 10 counterclockwise from 90 to 210 degrees.
- arc_inverted( rad=10, start_degrees=0, end_degrees=90)
+ arc_inverted(rad=10, start_degrees=0, end_degrees=90)
draws the portion of a 10x10 square NOT in a 90 degree circle of radius 10.
This is the shape you need to add to make fillets or remove to make rounds.
### Offsets
-To offset a set of points in one direction or another ( inside or outside a closed
-figure, for example) use `solid.utils.offset_points( point_arr, offset, inside=True)`
+To offset a set of points in one direction or another (inside or outside a closed
+figure, for example) use `solid.utils.offset_points(point_arr, offset, inside=True)`
Note that, for a non-convex figure, inside and outside may be non-intuitive. The
simple solution is to manually check that your offset is going in the direction you
@@ -235,7 +235,7 @@ intend, and change the boolean value of `inside` if you're not happy.
See the code for futher explanation. Improvements on the inside/outside algorithm would be welcome.
### Extrude Along Path
-`solid.utils.extrude_along_path( shape_pts, path_pts, scale_factors=None)`
+`solid.utils.extrude_along_path(shape_pts, path_pts, scale_factors=None)`
See [`solid/examples/path_extrude_example.py`](https://github.com/SolidCode/SolidPython/blob/master/solid/examples/path_extrude_example.py) for use.
@@ -243,8 +243,8 @@ See [`solid/examples/path_extrude_example.py`](https://github.com/SolidCode/Soli
### Basic color library
You can change an object's color by using the OpenSCAD ```color([rgba_array])``` function:
- transparent_blue = color( [0,0,1, 0.5])( cube(10)) # Specify with RGB[A]
- red_obj = color( Red)( cube( 10)) # Or use predefined colors
+ transparent_blue = color( [0,0,1, 0.5])(cube(10)) # Specify with RGB[A]
+ red_obj = color(Red)(cube(10)) # Or use predefined colors
These colors are pre-defined in solid.utils:
diff --git a/TODO_SolidPython.txt b/TODO_SolidPython.txt
index 4ecf66ec..bd480939 100644
--- a/TODO_SolidPython.txt
+++ b/TODO_SolidPython.txt
@@ -69,7 +69,7 @@ Completed:
-- Improving syntax so it's as close as possible to OpenSCAD's -ETJ 15 Feb 2011
-- By default, let polygon assume that connectivity between specified points (the paths argument) is
in the order specified in the points array. Without this, there's always
- boilerplate: polygon( points=arr, paths= range(len(arr)))
+ boilerplate: polygon(points=arr, paths= range(len(arr)))
-- Add 'segments' arguments to circle(), sphere() and cylinder()? This breaks
with OpenSCAD, but is simpler than circle(10).add_param('$fn', 30)
-- Unit testing.
diff --git a/solid/examples/animation_example.py b/solid/examples/animation_example.py
index 7a711362..94a08fb7 100755
--- a/solid/examples/animation_example.py
+++ b/solid/examples/animation_example.py
@@ -6,17 +6,17 @@
from solid import *
from solid.utils import *
-def my_animate( _time=0):
+def my_animate(_time=0):
# _time will range from 0 to 1, not including 1
rads = _time * 2 * 3.1416
rad = 15
- c = translate( [rad*cos(rads), rad*sin(rads)])( square( 10))
+ c = translate( [rad*cos(rads), rad*sin(rads)])(square(10))
return c
if __name__ == '__main__':
out_dir = sys.argv[1] if len(sys.argv) > 1 else os.curdir
- file_out = os.path.join( out_dir, 'animation_example.scad')
+ file_out = os.path.join(out_dir, 'animation_example.scad')
print("%(__file__)s: SCAD file written to: \n%(file_out)s"%vars())
@@ -28,7 +28,7 @@ def my_animate( _time=0):
# at the bottom of the OpenSCAD window
# - FPS & Steps are flexible. For a start, set both to 20
# play around from there
- scad_render_animated_file( my_animate, # A function that takes a float argument
+ scad_render_animated_file(my_animate, # A function that takes a float argument
# called '_time' in [0,1)
# and returns an OpenSCAD object
steps=20, # Number of steps to create one complete motion
diff --git a/solid/examples/append_solidpython_code.py b/solid/examples/append_solidpython_code.py
index f1f9d4d0..31fb914b 100755
--- a/solid/examples/append_solidpython_code.py
+++ b/solid/examples/append_solidpython_code.py
@@ -8,13 +8,13 @@
SEGMENTS = 48
def show_appended_python_code():
- a = cylinder( r=10, h=10, center=True) + up(5)( cylinder(r1=10, r2=0, h=10))
+ a = cylinder(r=10, h=10, center=True) + up(5)(cylinder(r1=10, r2=0, h=10))
return a
if __name__ == '__main__':
out_dir = sys.argv[1] if len(sys.argv) > 1 else os.curdir
- file_out = os.path.join( out_dir, 'append_solidpython_code.scad')
+ file_out = os.path.join(out_dir, 'append_solidpython_code.scad')
a = show_appended_python_code()
@@ -24,5 +24,5 @@ def show_appended_python_code():
# = bottom of the generated OpenSCAD code, so the final document
# = contains the easy-to-read python code as well as the SCAD.
# = ------------------------------------------------------------ =
- scad_render_to_file( a, file_out, include_orig_code=True)
+ scad_render_to_file(a, file_out, include_orig_code=True)
diff --git a/solid/examples/basic_geometry.py b/solid/examples/basic_geometry.py
index 7bbcc0c2..ca1c748b 100755
--- a/solid/examples/basic_geometry.py
+++ b/solid/examples/basic_geometry.py
@@ -16,13 +16,13 @@ def basic_geometry():
# left_piece uses standard OpenSCAD grammar (note the commas between
# block elements; OpenSCAD doesn't require this)
left_piece = union()(
- translate( [-15, 0, 0])(
- cube( [10, 5, 3], center=True)
+ translate([-15, 0, 0])(
+ cube([10, 5, 3], center=True)
),
- translate( [-10, 0, 0])(
+ translate([-10, 0, 0])(
difference()(
- cylinder( r=5, h=15, center=True),
- cylinder( r=4, h=16, center=True)
+ cylinder(r=5, h=15, center=True),
+ cylinder(r=4, h=16, center=True)
)
)
)
@@ -31,15 +31,15 @@ def basic_geometry():
# - (minus) is equivalent to difference() and * (star) is equivalent to intersection
# solid.utils also defines up(), down(), left(), right(), forward(), and back()
# for common transforms.
- right_piece = right( 15)( cube([10, 5, 3], center=True))
- cyl = cylinder( r=5, h=15, center=True) - cylinder( r=4, h=16, center=True)
- right_piece += right(10)( cyl)
+ right_piece = right(15)(cube([10, 5, 3], center=True))
+ cyl = cylinder(r=5, h=15, center=True) - cylinder(r=4, h=16, center=True)
+ right_piece += right(10)(cyl)
return union()(left_piece, right_piece)
if __name__ == '__main__':
out_dir = sys.argv[1] if len(sys.argv) > 1 else os.curdir
- file_out = os.path.join( out_dir, 'basic_geometry.scad')
+ file_out = os.path.join(out_dir, 'basic_geometry.scad')
a = basic_geometry()
@@ -49,4 +49,4 @@ def basic_geometry():
# the detail of arcs by changing the SEGMENTS variable. This can
# be expensive when making lots of small curves, but is otherwise
# useful.
- scad_render_to_file( a, file_out, file_header='$fn = %s;'%SEGMENTS)
\ No newline at end of file
+ scad_render_to_file(a, file_out, file_header='$fn = %s;'%SEGMENTS)
\ No newline at end of file
diff --git a/solid/examples/basic_scad_include.py b/solid/examples/basic_scad_include.py
index 6751ea7b..aa47cb35 100755
--- a/solid/examples/basic_scad_include.py
+++ b/solid/examples/basic_scad_include.py
@@ -9,17 +9,17 @@
def demo_scad_include():
# scad_to_include.scad includes a module called steps()
scad_path = os.path.join(os.path.dirname(__file__), "scad_to_include.scad")
- use( scad_path) # could also use 'include', but that has side-effects;
+ use(scad_path) # could also use 'include', but that has side-effects;
# 'use' just imports without executing any of the imported code
return steps(5)
if __name__ == '__main__':
out_dir = sys.argv[1] if len(sys.argv) > 1 else os.curdir
- file_out = os.path.join( out_dir, 'scad_include_example.scad')
+ file_out = os.path.join(out_dir, 'scad_include_example.scad')
a = demo_scad_include()
print("%(__file__)s: SCAD file written to: \n%(file_out)s"%vars())
- scad_render_to_file( a, file_out)
\ No newline at end of file
+ scad_render_to_file(a, file_out)
\ No newline at end of file
diff --git a/solid/examples/bom_scad.py b/solid/examples/bom_scad.py
index a2cc06b1..82a08333 100755
--- a/solid/examples/bom_scad.py
+++ b/solid/examples/bom_scad.py
@@ -34,16 +34,16 @@
doohickey_h = 5
def head():
- return cylinder( h=head_height, r =head_rad)
+ return cylinder(h=head_height, r =head_rad)
@bom_part("M3x16 Bolt", 0.12, currency="€")
-def m3_16( a=3):
+def m3_16(a=3):
bolt_height = 16
m = union()(
head(),
translate( [0,0, -bolt_height])(
- cylinder( r=m3_rad, h=bolt_height)
+ cylinder(r=m3_rad, h=bolt_height)
)
)
return m
@@ -55,7 +55,7 @@ def m3_12():
m = union()(
head(),
translate( [ 0, 0, -bolt_height])(
- cylinder( r=m3_rad, h=bolt_height)
+ cylinder(r=m3_rad, h=bolt_height)
)
)
return m
@@ -63,12 +63,12 @@ def m3_12():
@bom_part("M3 Nut", 0.04, currency="R$")
def m3_nut():
- hx = cylinder( r=nut_rad, h=nut_height)
+ hx = cylinder(r=nut_rad, h=nut_height)
hx.add_param('$fn', 6) # make the nut hexagonal
n = difference()(
hx,
translate([0,0,-EPSILON])(
- cylinder( r=m3_rad, h=nut_height+2*EPSILON )
+ cylinder(r=m3_rad, h=nut_height+2*EPSILON )
)
)
return n
@@ -81,9 +81,9 @@ def doohickey():
)
d = difference()(
cube([30, 10, doohickey_h], center=True),
- translate([-10, 0,0])( hole_cyl),
+ translate([-10, 0,0])(hole_cyl),
hole_cyl,
- translate([10,0,0])( hole_cyl)
+ translate([10,0,0])(hole_cyl)
)
return d
@@ -102,7 +102,7 @@ def assemble():
if __name__ == '__main__':
out_dir = sys.argv[1] if len(sys.argv) > 1 else os.curdir
- file_out = os.path.join( out_dir, 'BOM_example.scad')
+ file_out = os.path.join(out_dir, 'BOM_example.scad')
a = assemble()
@@ -111,4 +111,4 @@ def assemble():
print("%(__file__)s: SCAD file written to: \n%(file_out)s"%vars())
print(bom)
- scad_render_to_file( a, file_out)
+ scad_render_to_file(a, file_out)
diff --git a/solid/examples/hole_example.py b/solid/examples/hole_example.py
index 34a07b88..3f1f1851 100755
--- a/solid/examples/hole_example.py
+++ b/solid/examples/hole_example.py
@@ -14,7 +14,7 @@ def pipe_intersection_hole():
pipe_id = 10
seg_length = 30
- outer = cylinder( r=pipe_od, h=seg_length, center=True)
+ outer = cylinder(r=pipe_od, h=seg_length, center=True)
inner = cylinder(r=pipe_id, h=seg_length+2, center=True)
# By declaring that the internal void of pipe_a should
@@ -24,10 +24,10 @@ def pipe_intersection_hole():
# Any OpenSCAD / SolidPython object can be declared a hole(),
# and after that will always be empty
pipe_a = outer + hole()(inner)
- # Note that "pipe_a = outer - hole()( inner)" would work identically;
+ # Note that "pipe_a = outer - hole()(inner)" would work identically;
# inner will always be subtracted now that it's a hole
- pipe_b = rotate( a=90, v=FORWARD_VEC)( pipe_a)
+ pipe_b = rotate(a=90, v=FORWARD_VEC)(pipe_a)
return pipe_a + pipe_b
def pipe_intersection_no_hole():
@@ -35,11 +35,11 @@ def pipe_intersection_no_hole():
pipe_id = 10
seg_length = 30
- outer = cylinder( r=pipe_od, h=seg_length, center=True)
+ outer = cylinder(r=pipe_od, h=seg_length, center=True)
inner = cylinder(r=pipe_id, h=seg_length+2, center=True)
pipe_a = outer - inner
- pipe_b = rotate( a=90, v=FORWARD_VEC)( pipe_a)
+ pipe_b = rotate(a=90, v=FORWARD_VEC)(pipe_a)
# pipe_a and pipe_b are both hollow, but because
# their central voids aren't explicitly holes,
# the union of both pipes has unwanted internal walls
@@ -60,8 +60,8 @@ def multipart_hole():
# and then insert the same 'bolt' cylinder into it. The entire
# bolt rematins.
- b = cube( 10, center=True)
- c = cylinder( r=2, h=12, center=True)
+ b = cube(10, center=True)
+ c = cylinder(r=2, h=12, center=True)
# A cube with an explicit hole
not_part = b - hole()(c)
@@ -70,28 +70,28 @@ def multipart_hole():
is_part = part()(not_part.copy())
# This fits in the holes
- bolt = cylinder( r=1.5, h=14, center=True) + up(8)( cylinder( r=2.5, h=2.5, center=True))
+ bolt = cylinder(r=1.5, h=14, center=True) + up(8)(cylinder(r=2.5, h=2.5, center=True))
# The section of the bolt inside not_part disappears. The section
# of the bolt inside is_part is still there.
- a = not_part + bolt + right( 45)( is_part + bolt)
+ a = not_part + bolt + right(45)(is_part + bolt)
return a
if __name__ == '__main__':
out_dir = sys.argv[1] if len(sys.argv) > 1 else os.curdir
- file_out = os.path.join( out_dir, 'hole_example.scad')
+ file_out = os.path.join(out_dir, 'hole_example.scad')
# On the left, pipes with no explicit holes, which can give
# unexpected walls where we don't want them.
# On the right, we use the hole() function to fix the problem
- a = pipe_intersection_no_hole() + right( 45)(pipe_intersection_hole())
+ a = pipe_intersection_no_hole() + right(45)(pipe_intersection_hole())
# Below is an example of how to put objects into holes and have them
# still appear
- b = up( 40)( multipart_hole())
+ b = up(40)(multipart_hole())
a += b
print("%(__file__)s: SCAD file written to: \n%(file_out)s"%vars())
- scad_render_to_file( a, file_out, file_header='$fn = %s;'%SEGMENTS, include_orig_code=True)
+ scad_render_to_file(a, file_out, file_header='$fn = %s;'%SEGMENTS, include_orig_code=True)
diff --git a/solid/examples/koch.py b/solid/examples/koch.py
index 010ab0ce..d2f117db 100755
--- a/solid/examples/koch.py
+++ b/solid/examples/koch.py
@@ -9,12 +9,12 @@
ONE_THIRD = 1/3.0
-def affine_combination( a, b, weight=0.5):
+def affine_combination(a, b, weight=0.5):
'''
Note that weight is a fraction of the distance between self and other.
So... 0.33 is a point .33 of the way between self and other.
'''
- if hasattr( a, 'z'):
+ if hasattr(a, 'z'):
return Point3( (1-weight)*a.x + weight*b.x,
(1-weight)*a.y + weight*b.y,
(1-weight)*a.z + weight*b.z,
@@ -24,7 +24,7 @@ def affine_combination( a, b, weight=0.5):
(1-weight)*a.y + weight*b.y,
)
-def kochify_3d( a, b, c,
+def kochify_3d(a, b, c,
ab_weight=0.5, bc_weight=0.5, ca_weight=0.5,
pyr_a_weight=ONE_THIRD, pyr_b_weight=ONE_THIRD, pyr_c_weight=ONE_THIRD,
pyr_height_weight=ONE_THIRD
@@ -36,9 +36,9 @@ def kochify_3d( a, b, c,
pyr_height determines how far from the face the new pyramid's point will be
'''
triangles = []
- new_a = affine_combination( a, b, ab_weight)
- new_b = affine_combination( b, c, bc_weight)
- new_c = affine_combination( c, a, ca_weight)
+ new_a = affine_combination(a, b, ab_weight)
+ new_b = affine_combination(b, c, bc_weight)
+ new_c = affine_combination(c, a, ca_weight)
triangles.extend( [[a, new_a, new_c], [b, new_b, new_a], [c, new_c, new_b]])
@@ -46,16 +46,16 @@ def kochify_3d( a, b, c,
avg_pt_y = a.y*pyr_a_weight + b.y*pyr_b_weight + c.y*pyr_c_weight
avg_pt_z = a.z*pyr_a_weight + b.z*pyr_b_weight + c.z*pyr_c_weight
- center_pt = Point3( avg_pt_x, avg_pt_y, avg_pt_z)
+ center_pt = Point3(avg_pt_x, avg_pt_y, avg_pt_z)
# The top of the pyramid will be on a normal
ab_vec = b - a
bc_vec = c - b
ca_vec = a - c
- normal = ab_vec.cross( bc_vec).normalized()
+ normal = ab_vec.cross(bc_vec).normalized()
avg_side_length = (abs(ab_vec) + abs(bc_vec) + abs(ca_vec))/3
pyr_h = avg_side_length * pyr_height_weight
- pyr_pt = LineSegment3( center_pt, normal, pyr_h).p2
+ pyr_pt = LineSegment3(center_pt, normal, pyr_h).p2
triangles.extend([[new_a, pyr_pt, new_c], [new_b, pyr_pt, new_a], [new_c, pyr_pt, new_b]])
@@ -63,26 +63,26 @@ def kochify_3d( a, b, c,
return triangles
-def kochify( seg, height_ratio=0.33, left_loc= 0.33, midpoint_loc=0.5, right_loc= 0.66):
+def kochify(seg, height_ratio=0.33, left_loc= 0.33, midpoint_loc=0.5, right_loc= 0.66):
a, b = seg.p1, seg.p2
- l = affine_combination( a, b, left_loc)
- c = affine_combination( a, b, midpoint_loc)
- r = affine_combination( a, b, right_loc)
+ l = affine_combination(a, b, left_loc)
+ c = affine_combination(a, b, midpoint_loc)
+ r = affine_combination(a, b, right_loc)
# The point of the new triangle will be height_ratio * abs(seg) long,
# and run perpendicular to seg, through c.
perp = seg.v.cross().normalized()
c_height = height_ratio* abs(seg)
- perp_pt = LineSegment2( c, perp, -c_height).p2
+ perp_pt = LineSegment2(c, perp, -c_height).p2
# For the moment, assume perp_pt is on the right side of seg.
# Will confirm this later if needed
- return [ LineSegment2( a, l),
- LineSegment2( l, perp_pt),
- LineSegment2( perp_pt, r),
- LineSegment2( r, b)]
+ return [ LineSegment2(a, l),
+ LineSegment2(l, perp_pt),
+ LineSegment2(perp_pt, r),
+ LineSegment2(r, b)]
-def main_3d( out_dir):
+def main_3d(out_dir):
gens = 4
# Parameters
@@ -103,10 +103,10 @@ def main_3d( out_dir):
bx, by, bz = 100, 100,-100
cx, cy, cz = -100, 100, 100
dx, dy, dz = -100, -100, -100
- generations = [ [[ Point3( ax, ay, az), Point3( bx, by, bz), Point3( cx, cy, cz)],
- [ Point3( bx, by, bz), Point3( ax, ay, az), Point3( dx, dy, dz)],
- [ Point3( ax, ay, az), Point3( cx, cy, cz), Point3( dx, dy, dz)],
- [ Point3( cx, cy, cz), Point3( bx, by, bz), Point3( dx, dy, dz)],
+ generations = [ [[ Point3(ax, ay, az), Point3(bx, by, bz), Point3(cx, cy, cz)],
+ [ Point3(bx, by, bz), Point3(ax, ay, az), Point3(dx, dy, dz)],
+ [ Point3(ax, ay, az), Point3(cx, cy, cz), Point3(dx, dy, dz)],
+ [ Point3(cx, cy, cz), Point3(bx, by, bz), Point3(dx, dy, dz)],
]
]
@@ -114,15 +114,15 @@ def main_3d( out_dir):
for g in range(1, gens):
generations.append([])
for a, b, c in generations[g-1]:
- new_tris = kochify_3d( a, b, c,
+ new_tris = kochify_3d(a, b, c,
ab_weight, bc_weight, ca_weight,
pyr_a_weight, pyr_b_weight,pyr_c_weight,
pyr_height_weight)
# new_tris = kochify_3d( a, b, c)
- generations[g].extend( new_tris)
+ generations[g].extend(new_tris)
# Put all generations into SCAD
- orig_length = abs( generations[0][0][1] - generations[0][0][0])
+ orig_length = abs(generations[0][0][1] - generations[0][0][0])
for g, a_gen in enumerate(generations):
# Move each generation up in y so it doesn't overlap the others
h = orig_length *1.5 * g
@@ -137,17 +137,17 @@ def main_3d( out_dir):
# Do the SCAD
edges = [list(range(len(points)))]
- all_polys.add( up( h)(
- polyhedron( points=points, faces=faces)
+ all_polys.add(up(h)(
+ polyhedron(points=points, faces=faces)
)
)
- file_out = os.path.join( out_dir, 'koch_3d.scad')
+ file_out = os.path.join(out_dir, 'koch_3d.scad')
cur_file = __file__
print("%(cur_file)s: SCAD file written to: %(file_out)s"%vars())
- scad_render_to_file( all_polys, file_out, include_orig_code=True)
+ scad_render_to_file(all_polys, file_out, include_orig_code=True)
-def main( out_dir):
+def main(out_dir):
# Parameters
midpoint_weight = 0.5
height_ratio = 0.25
@@ -163,9 +163,9 @@ def main( out_dir):
ax, ay = 0, 0
bx, by = 100, 0
cx, cy = 50, 86.6
- base_seg1 = LineSegment2( Point2( ax, ay), Point2( cx, cy))
- base_seg2 = LineSegment2( Point2( cx, cy), Point2( bx, by))
- base_seg3 = LineSegment2( Point2( bx, by), Point2( ax, ay))
+ base_seg1 = LineSegment2( Point2(ax, ay), Point2(cx, cy))
+ base_seg2 = LineSegment2( Point2(cx, cy), Point2(bx, by))
+ base_seg3 = LineSegment2( Point2(bx, by), Point2(ax, ay))
generations = [[base_seg1, base_seg2, base_seg3]]
@@ -173,14 +173,14 @@ def main( out_dir):
for g in range(1, gens):
generations.append([])
for seg in generations[g-1]:
- generations[g].extend( kochify( seg, height_ratio, left_loc, midpoint_loc, right_loc))
- # generations[g].extend( kochify( seg))
+ generations[g].extend(kochify(seg, height_ratio, left_loc, midpoint_loc, right_loc))
+ # generations[g].extend(kochify(seg))
# # Put all generations into SCAD
- orig_length = abs( generations[0][0])
+ orig_length = abs(generations[0][0])
for g, a_gen in enumerate(generations):
points = [s.p1 for s in a_gen ]
- # points.append( a_gen[-1].p2) # add the last point
+ # points.append(a_gen[-1].p2) # add the last point
rect_offset = 10
@@ -192,15 +192,15 @@ def main( out_dir):
# Do the SCAD
edges = [list(range(len(points)))]
- all_polys.add( forward( h)( polygon(points=points, paths=edges )))
+ all_polys.add(forward(h)(polygon(points=points, paths=edges )))
- file_out = os.path.join( out_dir,'koch.scad')
+ file_out = os.path.join(out_dir,'koch.scad')
cur_file = __file__
print("%(cur_file)s: SCAD file written to: %(file_out)s "%vars())
- scad_render_to_file( all_polys, file_out, include_orig_code=True )
+ scad_render_to_file(all_polys, file_out, include_orig_code=True )
if __name__ == '__main__':
out_dir = sys.argv[1] if len(sys.argv) > 1 else os.curdir
- main_3d( out_dir)
- main( out_dir)
+ main_3d(out_dir)
+ main(out_dir)
diff --git a/solid/examples/path_extrude_example.py b/solid/examples/path_extrude_example.py
index 323041b1..a9b85b9d 100755
--- a/solid/examples/path_extrude_example.py
+++ b/solid/examples/path_extrude_example.py
@@ -9,22 +9,22 @@
SEGMENTS = 48
-def sinusoidal_ring( rad=25, segments=SEGMENTS):
+def sinusoidal_ring(rad=25, segments=SEGMENTS):
outline = []
- for i in range( segments):
+ for i in range(segments):
angle = i*360/segments
- x = rad * cos( radians(angle))
- y = rad * sin( radians(angle))
+ x = rad * cos(radians(angle))
+ y = rad * sin(radians(angle))
z = 2*sin(radians(angle*6))
- outline.append( Point3(x,y,z))
+ outline.append(Point3(x,y,z))
return outline
-def star( num_points=5, outer_rad=15, dip_factor=0.5):
+def star(num_points=5, outer_rad=15, dip_factor=0.5):
star_pts = []
for i in range(2*num_points):
rad = outer_rad - i%2 * dip_factor*outer_rad
- angle = radians( 360/(2*num_points) * i)
- star_pts.append(Point3( rad*cos(angle), rad*sin(angle), 0))
+ angle = radians(360/(2*num_points) * i)
+ star_pts.append(Point3(rad*cos(angle), rad*sin(angle), 0))
return star_pts
@@ -33,8 +33,8 @@ def extrude_example():
# Note the incorrect triangulation at the two ends of the path. This
# is because star isn't convex, and the triangulation algorithm for
# the two end caps only works for convex shapes.
- shape = star( num_points=5)
- path = sinusoidal_ring( rad=50)
+ shape = star(num_points=5)
+ path = sinusoidal_ring(rad=50)
# If scale_factors aren't included, they'll default to
# no scaling at each step along path. Here, let's
@@ -43,16 +43,16 @@ def extrude_example():
scales[0] = 2
scales[-1] = 2
- extruded = extrude_along_path( shape_pts=shape, path_pts=path, scale_factors=scales)
+ extruded = extrude_along_path(shape_pts=shape, path_pts=path, scale_factors=scales)
return extruded
if __name__ == '__main__':
out_dir = sys.argv[1] if len(sys.argv) > 1 else os.curdir
- file_out = os.path.join( out_dir, 'path_extrude_example.scad')
+ file_out = os.path.join(out_dir, 'path_extrude_example.scad')
a = extrude_example()
print("%(__file__)s: SCAD file written to: \n%(file_out)s"%vars())
- scad_render_to_file( a, file_out, include_orig_code=True)
+ scad_render_to_file(a, file_out, include_orig_code=True)
diff --git a/solid/examples/scad_to_include.scad b/solid/examples/scad_to_include.scad
index edd70fcc..a67ff9bb 100644
--- a/solid/examples/scad_to_include.scad
+++ b/solid/examples/scad_to_include.scad
@@ -1,5 +1,5 @@
external_var = false;
-module steps( howmany=3){
+module steps(howmany=3){
union(){
for (i=[0:howmany-1]){
translate( [i*10,0,0]){
@@ -8,7 +8,7 @@ module steps( howmany=3){
}
}
- if ( external_var){
+ if (external_var){
echo( "external_var passed in as true");
}
}
diff --git a/solid/examples/screw_thread_example.py b/solid/examples/screw_thread_example.py
index 01c2c463..5a173c4c 100755
--- a/solid/examples/screw_thread_example.py
+++ b/solid/examples/screw_thread_example.py
@@ -12,21 +12,21 @@
inner_rad = 40
screw_height=80
def assembly():
- section = screw_thread.default_thread_section( tooth_height=10, tooth_depth=5)
- s = screw_thread.thread( outline_pts=section, inner_rad = inner_rad,
+ section = screw_thread.default_thread_section(tooth_height=10, tooth_depth=5)
+ s = screw_thread.thread(outline_pts=section, inner_rad = inner_rad,
pitch= screw_height, length=screw_height, segments_per_rot=SEGMENTS)
#, neck_in_degrees=90, neck_out_degrees=90)
- c = cylinder( r=inner_rad, h=screw_height )
+ c = cylinder(r=inner_rad, h=screw_height )
return s + c
if __name__ == '__main__':
out_dir = sys.argv[1] if len(sys.argv) > 1 else os.curdir
- file_out = os.path.join( out_dir, 'screw_thread_example.scad')
+ file_out = os.path.join(out_dir, 'screw_thread_example.scad')
a = assembly()
print("%(__file__)s: SCAD file written to: \n%(file_out)s"%vars())
- scad_render_to_file( a, file_out, include_orig_code=True)
+ scad_render_to_file(a, file_out, include_orig_code=True)
diff --git a/solid/examples/sierpinski.py b/solid/examples/sierpinski.py
index 1555851d..1c97f732 100755
--- a/solid/examples/sierpinski.py
+++ b/solid/examples/sierpinski.py
@@ -17,12 +17,12 @@ class SierpinskiTetrahedron(object):
def __init__(self, four_points):
self.points = four_points
- def segments( self):
+ def segments(self):
indices = [(0,1), (0,2), (0,3), (1,2), (1,3), (2,3)]
return [(self.points[a], self.points[b]) for a,b in indices]
- def next_gen( self, midpoint_weight=0.5, jitter_range_vec=None):
- midpoints = [weighted_midpoint( s[0], s[1], weight=midpoint_weight, jitter_range_vec=jitter_range_vec) for s in self.segments()]
+ def next_gen(self, midpoint_weight=0.5, jitter_range_vec=None):
+ midpoints = [weighted_midpoint(s[0], s[1], weight=midpoint_weight, jitter_range_vec=jitter_range_vec) for s in self.segments()]
all_points = self.points + midpoints
new_tet_indices = [ (0, 4, 5, 6),
(4, 1, 7, 8),
@@ -31,30 +31,29 @@ def next_gen( self, midpoint_weight=0.5, jitter_range_vec=None):
new_tets = []
for four_ind in new_tet_indices:
tet_points = [all_points[i] for i in four_ind]
- new_tets.append( SierpinskiTetrahedron( tet_points))
+ new_tets.append(SierpinskiTetrahedron(tet_points))
return new_tets
- def scale( self, factor):
+ def scale(self, factor):
self.points = [[factor*d for d in p] for p in self.points]
- def scad_code( self):
+ def scad_code(self):
faces = [[0,1,2], [0,2,3], [0,3,1], [1,3,2]]
- return polyhedron( points=self.points, faces=faces, convexity =1)
+ return polyhedron(points=self.points, faces=faces, convexity =1)
-
-def distance( a, b):
+def distance(a, b):
return math.sqrt((a[0]-b[0])* (a[0]-b[0])+ (a[1]-b[1])* (a[1]-b[1])+ (a[2]-b[2])* (a[2]-b[2]))
-def weighted_midpoint( a, b, weight=0.5, jitter_range_vec=None):
+def weighted_midpoint(a, b, weight=0.5, jitter_range_vec=None):
# ignoring jitter_range_vec for now
x = weight*a[0] + (1-weight)*b[0]
y = weight*a[1] + (1-weight)*b[1]
z = weight*a[2] + (1-weight)*b[2]
- dist = distance( a, b)
+ dist = distance(a, b)
if jitter_range_vec:
x += (random.random()-.5) * dist * jitter_range_vec[0]
@@ -63,14 +62,14 @@ def weighted_midpoint( a, b, weight=0.5, jitter_range_vec=None):
return [x,y,z]
-def sierpinski_3d( generation, scale= 1, midpoint_weight=0.5, jitter_range_vec=None):
+def sierpinski_3d(generation, scale= 1, midpoint_weight=0.5, jitter_range_vec=None):
orig_tet = SierpinskiTetrahedron( [ [ 1.0, 1.0, 1.0],
- [-1.0, -1.0, 1.0],
- [-1.0, 1.0, -1.0],
- [ 1.0, -1.0, -1.0]])
+ [-1.0, -1.0, 1.0],
+ [-1.0, 1.0, -1.0],
+ [ 1.0, -1.0, -1.0]])
all_tets = [orig_tet]
- for i in range( generation):
- all_tets = [subtet for tet in all_tets for subtet in tet.next_gen( midpoint_weight, jitter_range_vec)]
+ for i in range(generation):
+ all_tets = [subtet for tet in all_tets for subtet in tet.next_gen(midpoint_weight, jitter_range_vec)]
if scale != 1:
for tet in all_tets:
@@ -88,17 +87,17 @@ def sierpinski_3d( generation, scale= 1, midpoint_weight=0.5, jitter_range_vec=N
# making it more interesting. Try:
# jitter_range_vec = [0.5,0, 0]
jitter_range_vec = None
- all_tets = sierpinski_3d( generations, scale=100, midpoint_weight=midpoint_weight, jitter_range_vec= jitter_range_vec)
+ all_tets = sierpinski_3d(generations, scale=100, midpoint_weight=midpoint_weight, jitter_range_vec= jitter_range_vec)
t = union()
for tet in all_tets:
# Create the scad code for all tetrahedra
- t.add( tet.scad_code())
+ t.add(tet.scad_code())
# Draw cubes at all intersections to make the shape manifold.
for p in tet.points:
- t.add( translate(p).add( cube(5, center=True)))
+ t.add(translate(p).add(cube(5, center=True)))
- file_out = os.path.join( out_dir, 'gasket_%s_gen.scad'%generations)
+ file_out = os.path.join(out_dir, 'gasket_%s_gen.scad'%generations)
print("%(__file__)s: SCAD file written to: \n%(file_out)s"%vars())
- scad_render_to_file( t, file_out)
\ No newline at end of file
+ scad_render_to_file(t, file_out)
\ No newline at end of file
diff --git a/solid/examples/solidpython_template.py b/solid/examples/solidpython_template.py
index 307d6464..35b72e8d 100755
--- a/solid/examples/solidpython_template.py
+++ b/solid/examples/solidpython_template.py
@@ -18,4 +18,4 @@ def assembly():
if __name__ == '__main__':
a = assembly()
- scad_render_to_file( a, file_header='$fn = %s;'%SEGMENTS, include_orig_code=True)
+ scad_render_to_file(a, file_header='$fn = %s;'%SEGMENTS, include_orig_code=True)
diff --git a/solid/patch_euclid.py b/solid/patch_euclid.py
index 8775a807..127d942c 100644
--- a/solid/patch_euclid.py
+++ b/solid/patch_euclid.py
@@ -6,10 +6,10 @@
# NOTE: The PyEuclid on PyPi doesn't include several elements added to
# the module as of 13 Feb 2013. Add them here until euclid supports them
-def as_arr_local( self):
+def as_arr_local(self):
return [ self.x, self.y, self.z]
-def set_length_local( self, length):
+def set_length_local(self, length):
d = self.magnitude()
if d:
factor = length/d
@@ -18,11 +18,11 @@ def set_length_local( self, length):
return self
-def _intersect_line3_line3( A, B):
+def _intersect_line3_line3(A, B):
# Connect A & B
# If the length of the connecting segment is 0, they intersect
# at the endpoint(s) of the connecting segment
- sol = euclid._connect_line3_line3( A, B)
+ sol = euclid._connect_line3_line3(A, B)
# TODO: Ray3 and LineSegment3 would like to be able to know
# if their intersection points fall within the segment.
if sol.magnitude_squared() < EPSILON:
@@ -33,9 +33,9 @@ def _intersect_line3_line3( A, B):
def run_patch():
- if 'as_arr' not in dir( Vector3):
+ if 'as_arr' not in dir(Vector3):
Vector3.as_arr = as_arr_local
- if 'set_length' not in dir( Vector3):
+ if 'set_length' not in dir(Vector3):
Vector3.set_length = set_length_local
if '_intersect_line3' not in dir(Line3):
Line3._intersect_line3 = _intersect_line3_line3
diff --git a/solid/screw_thread.py b/solid/screw_thread.py
index e49b320a..5b35e867 100755
--- a/solid/screw_thread.py
+++ b/solid/screw_thread.py
@@ -11,7 +11,7 @@
import solid.patch_euclid
solid.patch_euclid.run_patch()
-def thread( outline_pts, inner_rad, pitch, length, external=True, segments_per_rot=32,neck_in_degrees=0, neck_out_degrees=0):
+def thread(outline_pts, inner_rad, pitch, length, external=True, segments_per_rot=32,neck_in_degrees=0, neck_out_degrees=0):
'''
Sweeps outline_pts (an array of points describing a closed polygon in XY)
through a spiral.
@@ -53,20 +53,20 @@ def thread( outline_pts, inner_rad, pitch, length, external=True, segments_per_r
total_angle = 360.0*rotations
up_step = float(length) / (rotations*segments_per_rot)
# Add one to total_steps so we have total_steps *segments*
- total_steps = int(ceil( rotations * segments_per_rot)) + 1
+ total_steps = int(ceil(rotations * segments_per_rot)) + 1
step_angle = total_angle/ (total_steps -1)
all_points = []
all_tris = []
euc_up = Vector3( *UP_VEC)
- poly_sides = len( outline_pts)
+ poly_sides = len(outline_pts)
# Figure out how wide the tooth profile is
- min_bb, max_bb = bounding_box( outline_pts)
+ min_bb, max_bb = bounding_box(outline_pts)
outline_w = max_bb[0] - min_bb[0]
outline_h = max_bb[1] - min_bb[1]
- min_rad = max( 0, inner_rad-outline_w-EPSILON)
+ min_rad = max(0, inner_rad-outline_w-EPSILON)
max_rad = inner_rad + outline_w + EPSILON
# outline_pts, since they were created in 2D , are in the XY plane.
@@ -76,14 +76,14 @@ def thread( outline_pts, inner_rad, pitch, length, external=True, segments_per_r
euc_points = []
for p in outline_pts:
# If p is in [x, y] format, make it [x, y, 0]
- if len( p) == 2:
- p.append( 0)
+ if len(p) == 2:
+ p.append(0)
# [x, y, z] => [ x+inner_rad, z, y]
external_mult = 1 if external else -1
- s = Point3( external_mult*p[0], p[2], p[1]) # adding inner_rad, swapping Y & Z
- euc_points.append( s)
+ s = Point3(external_mult*p[0], p[2], p[1]) # adding inner_rad, swapping Y & Z
+ euc_points.append(s)
- for i in range( total_steps):
+ for i in range(total_steps):
angle = i*step_angle
elevation = i*up_step
@@ -101,17 +101,17 @@ def thread( outline_pts, inner_rad, pitch, length, external=True, segments_per_r
elif angle > total_angle - neck_in_degrees:
rad = neck_in_rad + int_ext_mult * (total_angle - angle)/neck_out_degrees * outline_w
- elev_vec = Vector3( rad, 0, elevation)
+ elev_vec = Vector3(rad, 0, elevation)
# create new points
for p in euc_points:
- pt = (p + elev_vec).rotate_around( axis=euc_up, theta=radians( angle))
- all_points.append( pt.as_arr())
+ pt = (p + elev_vec).rotate_around(axis=euc_up, theta=radians(angle))
+ all_points.append(pt.as_arr())
# Add the connectivity information
if i < total_steps -1:
ind = i*poly_sides
- for j in range( ind, ind + poly_sides - 1):
+ for j in range(ind, ind + poly_sides - 1):
all_tris.append( [ j, j+1, j+poly_sides])
all_tris.append( [ j+1, j+poly_sides+1, j+poly_sides])
all_tris.append( [ ind, ind + poly_sides-1+poly_sides, ind + poly_sides-1])
@@ -119,29 +119,29 @@ def thread( outline_pts, inner_rad, pitch, length, external=True, segments_per_r
# End triangle fans for beginning and end
last_loop = len(all_points) - poly_sides
- for i in range( poly_sides -2):
+ for i in range(poly_sides -2):
all_tris.append( [ 0, i+2, i+1])
all_tris.append( [ last_loop, last_loop + i+1, last_loop + i + 2])
# Make the polyhedron
- a = polyhedron( points=all_points, faces=all_tris)
+ a = polyhedron(points=all_points, faces=all_tris)
if external:
# Intersect with a cylindrical tube to make sure we fit into
# the correct dimensions
- tube = cylinder( r=inner_rad+outline_w+EPSILON, h=length, segments=segments_per_rot)
- tube -= cylinder( r=inner_rad, h=length, segments=segments_per_rot)
+ tube = cylinder(r=inner_rad+outline_w+EPSILON, h=length, segments=segments_per_rot)
+ tube -= cylinder(r=inner_rad, h=length, segments=segments_per_rot)
else:
# If the threading is internal, intersect with a central cylinder
# to make sure nothing else remains
- tube = cylinder( r=inner_rad, h=length, segments=segments_per_rot)
+ tube = cylinder(r=inner_rad, h=length, segments=segments_per_rot)
a *= tube
return render()(a)
-def default_thread_section( tooth_height, tooth_depth):
+def default_thread_section(tooth_height, tooth_depth):
# An isoceles triangle, tooth_height vertically, tooth_depth wide:
res = [ [ 0, -tooth_height/2],
[ tooth_depth, 0],
@@ -161,11 +161,11 @@ def assembly():
[ -1, 0, 0],
[ -1, -1, 0] ]
- a = thread( pts, inner_rad=10, pitch= 6, length=2, segments_per_rot=31,
+ a = thread(pts, inner_rad=10, pitch= 6, length=2, segments_per_rot=31,
neck_in_degrees=30, neck_out_degrees=30)
- return a + cylinder( 10+EPSILON, 2)
+ return a + cylinder(10+EPSILON, 2)
if __name__ == '__main__':
a = assembly()
- scad_render_to_file( a)
\ No newline at end of file
+ scad_render_to_file(a)
\ No newline at end of file
diff --git a/solid/solidpython.py b/solid/solidpython.py
index 25ae305f..914fa3c5 100755
--- a/solid/solidpython.py
+++ b/solid/solidpython.py
@@ -69,14 +69,14 @@
# Modifiers; These are implemented by calling e.g.
# obj.set_modifier( '*') or
# obj.set_modifier('disable')
- # disable( obj)
+ # disable(obj)
# on an existing object.
# {'name': 'background', 'args': [], 'kwargs': []}, # %{}
# {'name': 'debug', 'args': [], 'kwargs': []} , # #{}
# {'name': 'root', 'args': [], 'kwargs': []} , # !{}
# {'name': 'disable', 'args': [], 'kwargs': []} , # *{}
- {'name': 'intersection_for', 'args': ['n'], 'kwargs': []} , # e.g.: intersection_for( n=[1..6]){}
+ {'name': 'intersection_for', 'args': ['n'], 'kwargs': []} , # e.g.: intersection_for(n=[1..6]){}
# Unneeded
{'name': 'assign', 'args': [], 'kwargs': []} # Not really needed for Python. Also needs a **args argument so it accepts anything
@@ -84,36 +84,36 @@
# Some functions need custom code in them; put that code here
builtin_literals = {
- 'polygon': '''class polygon( openscad_object):
- def __init__( self, points, paths=None):
+ 'polygon': '''class polygon(OpenSCADObject):
+ def __init__(self, points, paths=None):
if not paths:
- paths = [ list(range( len( points)))]
- openscad_object.__init__( self, 'polygon', {'points':points, 'paths': paths})
+ paths = [ list(range(len(points)))]
+ OpenSCADObject.__init__(self, 'polygon', {'points':points, 'paths': paths})
''',
- 'hole':'''class hole( openscad_object):
- def __init__( self):
- openscad_object.__init__( self, 'hole', {})
- self.set_hole( True)
+ 'hole':'''class hole(OpenSCADObject):
+ def __init__(self):
+ OpenSCADObject.__init__(self, 'hole', {})
+ self.set_hole(True)
''',
- 'part':'''class part( openscad_object):
- def __init__( self):
- openscad_object.__init__(self, 'part', {})
- self.set_part_root( True)
+ 'part':'''class part(OpenSCADObject):
+ def __init__(self):
+ OpenSCADObject.__init__(self, 'part', {})
+ self.set_part_root(True)
''',
# Import, import_dxf, and import_stl all resolve to the same OpenSCAD keyword, 'import'
- 'import_':'''class import_( openscad_object):
- def __init__( self, file, origin=(0,0), layer=None):
- openscad_object.__init__(self, 'import', {'file':file, 'origin':origin, 'layer':layer})
+ 'import_':'''class import_(OpenSCADObject):
+ def __init__(self, file, origin=(0,0), layer=None):
+ OpenSCADObject.__init__(self, 'import', {'file':file, 'origin':origin, 'layer':layer})
''',
- 'import_dxf':'''class import_dxf( openscad_object):
- def __init__( self, file, origin=(0,0), layer=None):
- openscad_object.__init__(self, 'import', {'file':file, 'origin':origin, 'layer':layer})
+ 'import_dxf':'''class import_dxf(OpenSCADObject):
+ def __init__(self, file, origin=(0,0), layer=None):
+ OpenSCADObject.__init__(self, 'import', {'file':file, 'origin':origin, 'layer':layer})
''',
- 'import_stl':'''class import_stl( openscad_object):
- def __init__( self, file, origin=(0,0), layer=None):
- openscad_object.__init__(self, 'import', {'file':file, 'origin':origin, 'layer':layer})
+ 'import_stl':'''class import_stl(OpenSCADObject):
+ def __init__(self, file, origin=(0,0), layer=None):
+ OpenSCADObject.__init__(self, 'import', {'file':file, 'origin':origin, 'layer':layer})
'''
}
@@ -124,19 +124,19 @@ def __init__( self, file, origin=(0,0), layer=None):
# ================================
# = Modifier Convenience Methods =
# ================================
-def debug( openscad_obj):
+def debug(openscad_obj):
openscad_obj.set_modifier("#")
return openscad_obj
-def background( openscad_obj):
+def background(openscad_obj):
openscad_obj.set_modifier("%")
return openscad_obj
-def root( openscad_obj):
+def root(openscad_obj):
openscad_obj.set_modifier("!")
return openscad_obj
-def disable( openscad_obj):
+def disable(openscad_obj):
openscad_obj.set_modifier("*")
return openscad_obj
@@ -166,41 +166,41 @@ def use(scad_file_path, use_not_include=True):
raise Exception("Failed to import SCAD module '%(scad_file_path)s' with error: %(e)s "%vars())
# Once we have a list of all callables and arguments, dynamically
- # add openscad_object subclasses for all callables to the calling module's
+ # add OpenSCADObject subclasses for all callables to the calling module's
# namespace.
- symbols_dicts = extract_callable_signatures( scad_file_path)
+ symbols_dicts = extract_callable_signatures(scad_file_path)
for sd in symbols_dicts:
- class_str = new_openscad_class_str( sd['name'], sd['args'], sd['kwargs'], scad_file_path, use_not_include)
+ class_str = new_openscad_class_str(sd['name'], sd['args'], sd['kwargs'], scad_file_path, use_not_include)
# If this is called from 'include', we have to look deeper in the stack
# to find the right module to add the new class to.
stack_depth = 2 if use_not_include else 3
- exec(class_str, calling_module( stack_depth).__dict__)
+ exec(class_str, calling_module(stack_depth).__dict__)
return True
-def include( scad_file_path):
- return use( scad_file_path, use_not_include=False)
+def include(scad_file_path):
+ return use(scad_file_path, use_not_include=False)
# =========================================
# = Rendering Python code to OpenSCAD code=
# =========================================
-def _find_include_strings( obj):
+def _find_include_strings(obj):
include_strings = set()
- if isinstance( obj, included_openscad_object):
- include_strings.add( obj.include_string )
+ if isinstance(obj, IncludedOpenSCADObject):
+ include_strings.add(obj.include_string )
for child in obj.children:
- include_strings.update( _find_include_strings( child))
+ include_strings.update(_find_include_strings(child))
return include_strings
-def scad_render( scad_object, file_header=''):
+def scad_render(scad_object, file_header=''):
# Make this object the root of the tree
root = scad_object
# Scan the tree for all instances of
- # included_openscad_object, storing their strings
- include_strings = _find_include_strings( root)
+ # IncludedOpenSCADObject, storing their strings
+ include_strings = _find_include_strings(root)
# and render the string
includes = ''.join(include_strings) + "\n"
@@ -209,7 +209,7 @@ def scad_render( scad_object, file_header=''):
def scad_render_animated(func_to_animate, steps=20, back_and_forth=True, filepath=None, file_header=''):
# func_to_animate takes a single float argument, _time in [0, 1), and
- # returns an openscad_object instance.
+ # returns an OpenSCADObject instance.
#
# Outputs an OpenSCAD file with func_to_animate() evaluated at "steps"
# points between 0 & 1, with time never evaluated at exactly 1
@@ -238,7 +238,7 @@ def scad_render_animated(func_to_animate, steps=20, back_and_forth=True, filepat
# to be animated with an identical number of steps to the way it was
# created. -ETJ 28 Mar 2013
scad_obj = func_to_animate()
- include_strings = _find_include_strings( scad_obj)
+ include_strings = _find_include_strings(scad_obj)
# and render the string
includes = ''.join(include_strings) + "\n"
@@ -247,7 +247,7 @@ def scad_render_animated(func_to_animate, steps=20, back_and_forth=True, filepat
if back_and_forth:
steps *= 2
- for i in range( steps):
+ for i in range(steps):
time = i *1.0/steps
end_time = (i+1)*1.0/steps
eval_time = time
@@ -258,36 +258,35 @@ def scad_render_animated(func_to_animate, steps=20, back_and_forth=True, filepat
eval_time = time * 2
else:
eval_time = 2 - 2*time
- scad_obj = func_to_animate( _time=eval_time)
+ scad_obj = func_to_animate(_time=eval_time)
- scad_str = indent( scad_obj._render())
+ scad_str = indent(scad_obj._render())
rendered_string += ( "if ($t >= %(time)s && $t < %(end_time)s){"
" %(scad_str)s\n"
"}\n"%vars())
return rendered_string
-def scad_render_animated_file( func_to_animate, steps=20, back_and_forth=True, filepath=None, file_header='', include_orig_code=True):
+def scad_render_animated_file(func_to_animate, steps=20, back_and_forth=True, filepath=None, file_header='', include_orig_code=True):
rendered_string = scad_render_animated(func_to_animate, steps, back_and_forth, file_header)
return _write_code_to_file(rendered_string, filepath, include_orig_code)
-def scad_render_to_file( scad_object, filepath=None, file_header='', include_orig_code=True):
- rendered_string = scad_render( scad_object, file_header)
+def scad_render_to_file(scad_object, filepath=None, file_header='', include_orig_code=True):
+ rendered_string = scad_render(scad_object, file_header)
return _write_code_to_file(rendered_string, filepath, include_orig_code)
-
-
+
def _write_code_to_file(rendered_string, filepath=None, include_orig_code=True):
try:
- calling_file = os.path.abspath( calling_module(stack_depth=3).__file__)
+ calling_file = os.path.abspath(calling_module(stack_depth=3).__file__)
if include_orig_code:
- rendered_string += sp_code_in_scad_comment( calling_file)
+ rendered_string += sp_code_in_scad_comment(calling_file)
# This write is destructive, and ought to do some checks that the write
# was successful.
# If filepath isn't supplied, place a .scad file with the same name
# as the calling module next to it
if not filepath:
- filepath = os.path.splitext( calling_file)[0] + '.scad'
+ filepath = os.path.splitext(calling_file)[0] + '.scad'
except AttributeError as e:
# If no calling_file was found, this is being called from the terminal.
# We can't read original code from a file, so don't try,
@@ -296,12 +295,12 @@ def _write_code_to_file(rendered_string, filepath=None, include_orig_code=True):
if not filepath:
filepath = os.path.abspath('.') + "/solid.scad"
- f = open( filepath,"w")
- f.write( rendered_string)
+ f = open(filepath,"w")
+ f.write(rendered_string)
f.close()
return True
-def sp_code_in_scad_comment( calling_file):
+def sp_code_in_scad_comment(calling_file):
# Once a SCAD file has been created, it's difficult to reconstruct
# how it got there, since it has no variables, modules, etc. So, include
# the Python code that generated the scad code as comments at the end of
@@ -328,7 +327,7 @@ def sp_code_in_scad_comment( calling_file):
# =========================
# = Internal Utilities =
# =========================
-class openscad_object( object):
+class OpenSCADObject(object):
def __init__(self, name, params):
self.name = name
self.params = params
@@ -339,17 +338,17 @@ def __init__(self, name, params):
self.has_hole_children = False
self.is_part_root = False
- def set_hole( self, is_hole=True):
+ def set_hole(self, is_hole=True):
self.is_hole = is_hole
return self
- def set_part_root( self, is_root=True):
+ def set_part_root(self, is_root=True):
self.is_part_root = is_root
return self
- def find_hole_children( self, path=None):
+ def find_hole_children(self, path=None):
# Because we don't force a copy every time we re-use a node
- # (e.g a = cylinder(2, 6); b = right( 10) (a)
+ # (e.g a = cylinder(2, 6); b = right(10) (a)
# the identical 'a' object appears in the tree twice),
# we can't count on an object's 'parent' field to trace its
# path to the root. Instead, keep track explicitly
@@ -357,9 +356,9 @@ def find_hole_children( self, path=None):
hole_kids = []
for child in self.children:
- path.append( child)
+ path.append(child)
if child.is_hole:
- hole_kids.append( child)
+ hole_kids.append(child)
# Mark all parents as having a hole child
for p in path:
p.has_hole_children = True
@@ -368,7 +367,7 @@ def find_hole_children( self, path=None):
continue
# Otherwise, look below us for children
else:
- hole_kids += child.find_hole_children( path)
+ hole_kids += child.find_hole_children(path)
path.pop( )
return hole_kids
@@ -402,7 +401,7 @@ def _render(self, render_holes=False):
# And render after everything else
if not render_holes and child.is_hole:
continue
- s += child._render( render_holes)
+ s += child._render(render_holes)
# Then render self and prepend/wrap it around the children
# I've added designated parts and explicit holes to SolidPython.
@@ -412,7 +411,7 @@ def _render(self, render_holes=False):
elif not self.children:
s = self._render_str_no_children() + ";"
else:
- s = self._render_str_no_children() + " {" + indent( s) + "\n}"
+ s = self._render_str_no_children() + " {" + indent(s) + "\n}"
# If this is the root object or the top of a separate part,
# find all holes and subtract them after all positive geometry
@@ -428,7 +427,7 @@ def _render(self, render_holes=False):
s = "\ndifference(){" + indent(s) + " /* End Holes */ \n}"
return s
- def _render_str_no_children( self):
+ def _render_str_no_children(self):
s = "\n" + self.modifier + self.name + "("
first = True
@@ -465,7 +464,7 @@ def _render_str_no_children( self):
s += ")"
return s
- def _render_hole_children( self):
+ def _render_hole_children(self):
# Run down the tree, rendering only those nodes
# that are holes or have holes beneath them
if not self.has_hole_children:
@@ -473,10 +472,10 @@ def _render_hole_children( self):
s = ""
for child in self.children:
if child.is_hole:
- s += child._render( render_holes=True)
+ s += child._render(render_holes=True)
elif child.has_hole_children:
# Holes exist in the compiled tree in two pieces:
- # The shapes of the holes themselves, ( an object for which
+ # The shapes of the holes themselves, (an object for which
# obj.is_hole is True, and all its children) and the
# transforms necessary to put that hole in place, which
# are inherited from non-hole geometry.
@@ -498,29 +497,29 @@ def _render_hole_children( self):
if self.name in non_rendered_classes:
pass
else:
- s = self._render_str_no_children() + "{" + indent( s) + "\n}"
+ s = self._render_str_no_children() + "{" + indent(s) + "\n}"
return s
def add(self, child):
'''
- if child is a single object, assume it's an openscad_object and
+ if child is a single object, assume it's an OpenSCADObject and
add it to self.children
- if child is a list, assume its members are all openscad_objects and
+ if child is a list, assume its members are all OpenSCADObjects and
add them all to self.children
'''
- if isinstance( child, (list, tuple)):
+ if isinstance(child, (list, tuple)):
# __call__ passes us a list inside a tuple, but we only care
# about the list, so skip single-member tuples containing lists
- if len( child) == 1 and isinstance(child[0], (list, tuple)):
+ if len(child) == 1 and isinstance(child[0], (list, tuple)):
child = child[0]
- [self.add( c ) for c in child]
+ [self.add(c ) for c in child]
else:
- self.children.append( child)
- child.set_parent( self)
+ self.children.append(child)
+ child.set_parent(self)
return self
- def set_parent( self, parent):
+ def set_parent(self, parent):
self.parent = parent
def add_param(self, k, v):
@@ -529,7 +528,7 @@ def add_param(self, k, v):
self.params[k] = v
return self
- def copy( self):
+ def copy(self):
# Provides a copy of this object and all children,
# but doesn't copy self.parent, meaning the new object belongs
# to a different tree
@@ -545,15 +544,15 @@ def copy( self):
self.params['segments'] = self.params.pop('$fn')
other = globals()[ self.name]( **self.params)
- other.set_modifier( self.modifier)
- other.set_hole( self.is_hole)
- other.set_part_root( self.is_part_root)
+ other.set_modifier(self.modifier)
+ other.set_hole(self.is_hole)
+ other.set_part_root(self.is_part_root)
other.has_hole_children = self.has_hole_children
for c in self.children:
- other.add( c.copy())
+ other.add(c.copy())
return other
- def __call__( self, *args):
+ def __call__(self, *args):
'''
Adds all objects in args to self. This enables OpenSCAD-like syntax,
e.g.:
@@ -567,33 +566,33 @@ def __call__( self, *args):
def __add__(self, x):
'''
This makes u = a+b identical to:
- u = union()( a, b )
+ u = union()(a, b )
'''
return union()(self, x)
def __sub__(self, x):
'''
This makes u = a - b identical to:
- u = difference()( a, b )
+ u = difference()(a, b )
'''
return difference()(self, x)
def __mul__(self, x):
'''
This makes u = a * b identical to:
- u = intersection()( a, b )
+ u = intersection()(a, b )
'''
return intersection()(self, x)
-class included_openscad_object( openscad_object):
+class IncludedOpenSCADObject(OpenSCADObject):
'''
- Identical to openscad_object, but each subclass of included_openscad_object
+ Identical to OpenSCADObject, but each subclass of IncludedOpenSCADObject
represents imported scad code, so each instance needs to store the path
to the scad file it's included from.
'''
- def __init__( self, name, params, include_file_path, use_not_include=False, **kwargs):
- self.include_file_path = self._get_include_path( include_file_path)
+ def __init__(self, name, params, include_file_path, use_not_include=False, **kwargs):
+ self.include_file_path = self._get_include_path(include_file_path)
if use_not_include:
self.include_string = 'use <%s>\n'%self.include_file_path
@@ -602,9 +601,9 @@ def __init__( self, name, params, include_file_path, use_not_include=False, **kw
# Just pass any extra arguments straight on to OpenSCAD; it'll accept them
if kwargs:
- params.update( kwargs)
+ params.update(kwargs)
- openscad_object.__init__(self, name, params)
+ OpenSCADObject.__init__(self, name, params)
def _get_include_path(self, include_file_path):
# Look through sys.path for anyplace we can find a valid file ending
@@ -622,7 +621,7 @@ def _get_include_path(self, include_file_path):
"%(include_file_path)s in sys.path"%vars())
-def calling_module( stack_depth=2):
+def calling_module(stack_depth=2):
'''
Returns the module *2* back in the frame stack. That means:
code in module A calls code in module B, which asks calling_module()
@@ -636,7 +635,7 @@ def calling_module( stack_depth=2):
Got that?
'''
frm = inspect.stack()[stack_depth]
- calling_mod = inspect.getmodule( frm[0])
+ calling_mod = inspect.getmodule(frm[0])
# If calling_mod is None, this is being called from an interactive session.
# Return that module. (Note that __main__ doesn't have a __file__ attr,
# but that's caught elsewhere.)
@@ -644,7 +643,7 @@ def calling_module( stack_depth=2):
import __main__ as calling_mod
return calling_mod
-def new_openscad_class_str( class_name, args=[], kwargs=[], include_file_path=None, use_not_include=True):
+def new_openscad_class_str(class_name, args=[], kwargs=[], include_file_path=None, use_not_include=True):
args_str = ''
args_pairs = ''
@@ -668,15 +667,15 @@ def new_openscad_class_str( class_name, args=[], kwargs=[], include_file_path=No
# NOTE the explicit import of 'solid' below. This is a fix for:
# https://github.com/SolidCode/SolidPython/issues/20 -ETJ 16 Jan 2014
result = ("import solid\n"
- "class %(class_name)s( solid.included_openscad_object):\n"
+ "class %(class_name)s(solid.IncludedOpenSCADObject):\n"
" def __init__(self%(args_str)s, **kwargs):\n"
- " 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"
+ " solid.IncludedOpenSCADObject.__init__(self, '%(class_name)s', {%(args_pairs)s }, include_file_path='%(include_file_path)s', use_not_include=%(use_not_include)s, **kwargs )\n"
" \n"
"\n"%vars())
else:
- result = ("class %(class_name)s( openscad_object):\n"
+ result = ("class %(class_name)s(OpenSCADObject):\n"
" def __init__(self%(args_str)s):\n"
- " openscad_object.__init__(self, '%(class_name)s', {%(args_pairs)s })\n"
+ " OpenSCADObject.__init__(self, '%(class_name)s', {%(args_pairs)s })\n"
" \n"
"\n"%vars())
@@ -708,19 +707,19 @@ def indent(s):
# ===========
# = Parsing =
# ===========
-def extract_callable_signatures( scad_file_path):
+def extract_callable_signatures(scad_file_path):
with open(scad_file_path) as f:
scad_code_str = f.read()
- return parse_scad_callables( scad_code_str)
+ return parse_scad_callables(scad_code_str)
-def parse_scad_callables( scad_code_str):
+def parse_scad_callables(scad_code_str):
callables = []
# Note that this isn't comprehensive; tuples or nested data structures in
# a module definition will defeat it.
# Current implementation would throw an error if you tried to call a(x, y)
- # since Python would expect a( x); OpenSCAD itself ignores extra arguments,
+ # since Python would expect a(x); OpenSCAD itself ignores extra arguments,
# but that's not really preferable behavior
# TODO: write a pyparsing grammar for OpenSCAD, or, even better, use the yacc parse grammar
@@ -739,7 +738,7 @@ def parse_scad_callables( scad_code_str):
# remove all comments from SCAD code
scad_code_str = re.sub(no_comments_re,'', scad_code_str)
# get all SCAD callables
- mod_matches = re.finditer( mod_re, scad_code_str)
+ mod_matches = re.finditer(mod_re, scad_code_str)
for m in mod_matches:
callable_name = m.group('callable_name')
@@ -747,13 +746,13 @@ def parse_scad_callables( scad_code_str):
kwargs = []
all_args = m.group('all_args')
if all_args:
- arg_matches = re.finditer( args_re, all_args)
+ arg_matches = re.finditer(args_re, all_args)
for am in arg_matches:
arg_name = am.group('arg_name')
if am.group('default_val'):
- kwargs.append( arg_name)
+ kwargs.append(arg_name)
else:
- args.append( arg_name)
+ args.append(arg_name)
callables.append( { 'name':callable_name, 'args': args, 'kwargs':kwargs})
@@ -766,7 +765,7 @@ def parse_scad_callables( scad_code_str):
if sym_dict['name'] in builtin_literals:
class_str = builtin_literals[ sym_dict['name']]
else:
- class_str = new_openscad_class_str( sym_dict['name'], sym_dict['args'], sym_dict['kwargs'])
+ class_str = new_openscad_class_str(sym_dict['name'], sym_dict['args'], sym_dict['kwargs'])
exec(class_str)
diff --git a/solid/t_slots.py b/solid/t_slots.py
index b2564c2a..59579053 100755
--- a/solid/t_slots.py
+++ b/solid/t_slots.py
@@ -21,7 +21,7 @@
# It might be easier to have the edges NOT overlap at all and then have tabs
# for the slots added programmatically. -ETJ 06 Mar 2013
-def t_slot_holes( poly, point=None, edge_vec=RIGHT_VEC, screw_vec=DOWN_VEC, screw_type='m3', screw_length=16, material_thickness=DFM, kerf=0 ):
+def t_slot_holes(poly, point=None, edge_vec=RIGHT_VEC, screw_vec=DOWN_VEC, screw_type='m3', screw_length=16, material_thickness=DFM, kerf=0 ):
'''
Cuts a screw hole and two notches in poly so they'll
interface with the features cut by t_slot()
@@ -38,29 +38,29 @@ def t_slot_holes( poly, point=None, edge_vec=RIGHT_VEC, screw_vec=DOWN_VEC, scre
TODO: add kerf calculations
'''
point = point if point else ORIGIN
- point = euclidify( point, Point3)
- screw_vec = euclidify( screw_vec, Vector3)
- edge_vec = euclidify( edge_vec, Vector3)
+ point = euclidify(point, Point3)
+ screw_vec = euclidify(screw_vec, Vector3)
+ edge_vec = euclidify(edge_vec, Vector3)
- src_up = screw_vec.cross( edge_vec)
+ src_up = screw_vec.cross(edge_vec)
a_hole = square( [tab_width, material_thickness], center=True)
move_hole = tab_offset + tab_width/2
- tab_holes = left( move_hole)( a_hole) + right( move_hole)( a_hole)
+ tab_holes = left(move_hole)(a_hole) + right(move_hole)(a_hole)
# Only valid for m3-m5 screws now
- screw_dict = screw_dimensions.get( screw_type.lower())
+ screw_dict = screw_dimensions.get(screw_type.lower())
if screw_dict:
screw_w = screw_dict['screw_outer_diam']
else:
raise ValueError( "Don't have screw dimensions for requested screw size %s"%screw_type)
# add the screw hole
- tab_holes += circle( screw_w/2) # NOTE: needs any extra space?
+ tab_holes += circle(screw_w/2) # NOTE: needs any extra space?
- tab_holes = transform_to_point( tab_holes, point, dest_normal=screw_vec, src_normal=UP_VEC, src_up=src_up)
+ tab_holes = transform_to_point(tab_holes, point, dest_normal=screw_vec, src_normal=UP_VEC, src_up=src_up)
return poly - tab_holes
@@ -85,20 +85,20 @@ def t_slot( poly, point=None, screw_vec=DOWN_VEC, face_normal=UP_VEC, scre
TODO: include kerf in calculations
'''
point = point if point else ORIGIN
- point = euclidify( point, Point3)
- screw_vec = euclidify( screw_vec, Vector3)
- face_normal = euclidify( face_normal, Vector3)
+ point = euclidify(point, Point3)
+ screw_vec = euclidify(screw_vec, Vector3)
+ face_normal = euclidify(face_normal, Vector3)
- tab = tab_poly( material_thickness=material_thickness)
- slot = nut_trap_slot( screw_type, screw_length, material_thickness=material_thickness)
+ tab = tab_poly(material_thickness=material_thickness)
+ slot = nut_trap_slot(screw_type, screw_length, material_thickness=material_thickness)
# NOTE: dest_normal & src_normal are the same. This should matter, right?
- tab = transform_to_point( tab, point, dest_normal=face_normal, src_normal=face_normal, src_up=-screw_vec)
- slot = transform_to_point( slot, point, dest_normal=face_normal, src_normal=face_normal, src_up=-screw_vec)
+ tab = transform_to_point(tab, point, dest_normal=face_normal, src_normal=face_normal, src_up=-screw_vec)
+ slot = transform_to_point(slot, point, dest_normal=face_normal, src_normal=face_normal, src_up=-screw_vec)
return poly + tab - slot
-def tab_poly( material_thickness=DFM):
+def tab_poly(material_thickness=DFM):
r = [ [ tab_width + tab_offset, -EPSILON],
[ tab_offset, -EPSILON],
@@ -109,7 +109,7 @@ def tab_poly( material_thickness=DFM):
tab_pts = l + r
tab_faces = [[0,1,2,3], [4,5,6,7]]
- tab = polygon( tab_pts, tab_faces)
+ tab = polygon(tab_pts, tab_faces)
# Round off the top points so tabs slide in more easily
round_tabs = False
@@ -119,13 +119,13 @@ def tab_poly( material_thickness=DFM):
[l[1], l[2], l[3]],
[l[2], l[3], l[0]],
]
- tab = fillet_2d( three_point_sets=points_to_round, orig_poly=tab,
+ tab = fillet_2d(three_point_sets=points_to_round, orig_poly=tab,
fillet_rad=1, remove_material=True)
return tab
-def nut_trap_slot( screw_type='m3', screw_length=16, material_thickness=DFM):
+def nut_trap_slot(screw_type='m3', screw_length=16, material_thickness=DFM):
# This shape has a couple uses.
# 1) Right angle joint between two pieces of material.
# A bolt goes through the second piece and into the first.
@@ -137,7 +137,7 @@ def nut_trap_slot( screw_type='m3', screw_length=16, material_thickness=DFM):
# Only valid for m3-m5 screws now
- screw_dict = screw_dimensions.get( screw_type.lower())
+ screw_dict = screw_dimensions.get(screw_type.lower())
if screw_dict:
screw_w = screw_dict['screw_outer_diam']
screw_w2 = screw_w/2
@@ -164,11 +164,11 @@ def nut_trap_slot( screw_type='m3', screw_length=16, material_thickness=DFM):
# TODO: round off top corners of slot
# Add circles around t edges to prevent acrylic breakage
- slot = polygon( slot_pts)
+ slot = polygon(slot_pts)
slot = union()(
slot,
- translate( [nut_hole_x, nut_loc])( circle( tab_curve_rad)),
- translate( [-nut_hole_x, nut_loc])( circle( tab_curve_rad))
+ translate( [nut_hole_x, nut_loc])(circle(tab_curve_rad)),
+ translate( [-nut_hole_x, nut_loc])(circle(tab_curve_rad))
)
return render()(slot)
@@ -179,4 +179,4 @@ def assembly():
if __name__ == '__main__':
a = assembly()
- scad_render_to_file( a, file_header='$fn = %s;'%SEGMENTS, include_orig_code=True)
+ scad_render_to_file(a, file_header='$fn = %s;'%SEGMENTS, include_orig_code=True)
diff --git a/solid/test/test_screw_thread.py b/solid/test/test_screw_thread.py
index 899c69d7..f27cdc97 100755
--- a/solid/test/test_screw_thread.py
+++ b/solid/test/test_screw_thread.py
@@ -16,30 +16,30 @@ class TestScrewThread(DiffOutput):
def test_thread(self):
tooth_height = 10
tooth_depth = 5
- outline = default_thread_section( tooth_height=tooth_height, tooth_depth=tooth_depth)
- actual_obj = thread( outline_pts=outline, inner_rad=20, pitch=tooth_height,
+ outline = default_thread_section(tooth_height=tooth_height, tooth_depth=tooth_depth)
+ actual_obj = thread(outline_pts=outline, inner_rad=20, pitch=tooth_height,
length=0.75*tooth_height, segments_per_rot=SEGMENTS,
neck_in_degrees=45, neck_out_degrees=45)
- actual = scad_render( actual_obj)
+ actual = scad_render(actual_obj)
expected = '\n\nrender() {\n\tintersection() {\n\t\tpolyhedron(faces = [[0, 1, 3], [1, 4, 3], [1, 2, 4], [2, 5, 4], [0, 5, 2], [0, 3, 5], [3, 4, 6], [4, 7, 6], [4, 5, 7], [5, 8, 7], [3, 8, 5], [3, 6, 8], [6, 7, 9], [7, 10, 9], [7, 8, 10], [8, 11, 10], [6, 11, 8], [6, 9, 11], [9, 10, 12], [10, 13, 12], [10, 11, 13], [11, 14, 13], [9, 14, 11], [9, 12, 14], [12, 13, 15], [13, 16, 15], [13, 14, 16], [14, 17, 16], [12, 17, 14], [12, 15, 17], [15, 16, 18], [16, 19, 18], [16, 17, 19], [17, 20, 19], [15, 20, 17], [15, 18, 20], [0, 2, 1], [18, 19, 20]], points = [[14.9900000000, 0.0000000000, -5.0000000000], [19.9900000000, 0.0000000000, 0.0000000000], [14.9900000000, 0.0000000000, 5.0000000000], [14.1421356237, 14.1421356237, -3.7500000000], [17.6776695297, 17.6776695297, 1.2500000000], [14.1421356237, 14.1421356237, 6.2500000000], [0.0000000000, 20.0000000000, -2.5000000000], [0.0000000000, 25.0000000000, 2.5000000000], [0.0000000000, 20.0000000000, 7.5000000000], [-14.1421356237, 14.1421356237, -1.2500000000], [-17.6776695297, 17.6776695297, 3.7500000000], [-14.1421356237, 14.1421356237, 8.7500000000], [-20.0000000000, 0.0000000000, 0.0000000000], [-25.0000000000, 0.0000000000, 5.0000000000], [-20.0000000000, 0.0000000000, 10.0000000000], [-14.1421356237, -14.1421356237, 1.2500000000], [-17.6776695297, -17.6776695297, 6.2500000000], [-14.1421356237, -14.1421356237, 11.2500000000], [-0.0000000000, -14.9900000000, 2.5000000000], [-0.0000000000, -19.9900000000, 7.5000000000], [-0.0000000000, -14.9900000000, 12.5000000000]]);\n\t\tdifference() {\n\t\t\tcylinder($fn = 8, h = 7.5000000000, r = 25.0100000000);\n\t\t\tcylinder($fn = 8, h = 7.5000000000, r = 20);\n\t\t}\n\t}\n}'
- self.assertEqual( expected, actual)
+ self.assertEqual(expected, actual)
- def test_thread_internal( self):
+ def test_thread_internal(self):
tooth_height = 10
tooth_depth = 5
- outline = default_thread_section( tooth_height=tooth_height, tooth_depth=tooth_depth)
- actual_obj = thread( outline_pts=outline, inner_rad=20, pitch=2*tooth_height,
+ outline = default_thread_section(tooth_height=tooth_height, tooth_depth=tooth_depth)
+ actual_obj = thread(outline_pts=outline, inner_rad=20, pitch=2*tooth_height,
length=2*tooth_height, segments_per_rot=SEGMENTS,
neck_in_degrees=45, neck_out_degrees=45,
external=False)
- actual = scad_render( actual_obj)
+ actual = scad_render(actual_obj)
expected = '\n\nrender() {\n\tintersection() {\n\t\tpolyhedron(faces = [[0, 1, 3], [1, 4, 3], [1, 2, 4], [2, 5, 4], [0, 5, 2], [0, 3, 5], [3, 4, 6], [4, 7, 6], [4, 5, 7], [5, 8, 7], [3, 8, 5], [3, 6, 8], [6, 7, 9], [7, 10, 9], [7, 8, 10], [8, 11, 10], [6, 11, 8], [6, 9, 11], [9, 10, 12], [10, 13, 12], [10, 11, 13], [11, 14, 13], [9, 14, 11], [9, 12, 14], [12, 13, 15], [13, 16, 15], [13, 14, 16], [14, 17, 16], [12, 17, 14], [12, 15, 17], [15, 16, 18], [16, 19, 18], [16, 17, 19], [17, 20, 19], [15, 20, 17], [15, 18, 20], [18, 19, 21], [19, 22, 21], [19, 20, 22], [20, 23, 22], [18, 23, 20], [18, 21, 23], [21, 22, 24], [22, 25, 24], [22, 23, 25], [23, 26, 25], [21, 26, 23], [21, 24, 26], [0, 2, 1], [24, 25, 26]], points = [[25.0100000000, 0.0000000000, -5.0000000000], [20.0100000000, 0.0000000000, 0.0000000000], [25.0100000000, 0.0000000000, 5.0000000000], [14.1421356237, 14.1421356237, -2.5000000000], [10.6066017178, 10.6066017178, 2.5000000000], [14.1421356237, 14.1421356237, 7.5000000000], [0.0000000000, 20.0000000000, 0.0000000000], [0.0000000000, 15.0000000000, 5.0000000000], [0.0000000000, 20.0000000000, 10.0000000000], [-14.1421356237, 14.1421356237, 2.5000000000], [-10.6066017178, 10.6066017178, 7.5000000000], [-14.1421356237, 14.1421356237, 12.5000000000], [-20.0000000000, 0.0000000000, 5.0000000000], [-15.0000000000, 0.0000000000, 10.0000000000], [-20.0000000000, 0.0000000000, 15.0000000000], [-14.1421356237, -14.1421356237, 7.5000000000], [-10.6066017178, -10.6066017178, 12.5000000000], [-14.1421356237, -14.1421356237, 17.5000000000], [-0.0000000000, -20.0000000000, 10.0000000000], [-0.0000000000, -15.0000000000, 15.0000000000], [-0.0000000000, -20.0000000000, 20.0000000000], [14.1421356237, -14.1421356237, 12.5000000000], [10.6066017178, -10.6066017178, 17.5000000000], [14.1421356237, -14.1421356237, 22.5000000000], [25.0100000000, -0.0000000000, 15.0000000000], [20.0100000000, -0.0000000000, 20.0000000000], [25.0100000000, -0.0000000000, 25.0000000000]]);\n\t\tcylinder($fn = 8, h = 20, r = 20);\n\t}\n}'
- self.assertEqual( expected, actual)
+ self.assertEqual(expected, actual)
def test_default_thread_section(self):
expected = [[0, -5], [5, 0], [0, 5]]
- actual = default_thread_section( tooth_height=10, tooth_depth=5)
- self.assertEqual( expected, actual)
+ actual = default_thread_section(tooth_height=10, tooth_depth=5)
+ self.assertEqual(expected, actual)
diff --git a/solid/test/test_solidpython.py b/solid/test/test_solidpython.py
index 2def8b08..93921f02 100755
--- a/solid/test/test_solidpython.py
+++ b/solid/test/test_solidpython.py
@@ -50,55 +50,55 @@ def expand_scad_path(self, filename):
return full_path
return None
- def test_infix_union( self):
+ def test_infix_union(self):
a = cube(2)
- b = sphere( 2)
+ b = sphere(2)
expected = '\n\nunion() {\n\tcube(size = 2);\n\tsphere(r = 2);\n}'
- actual = scad_render( a+b)
- self.assertEqual( expected, actual)
+ actual = scad_render(a+b)
+ self.assertEqual(expected, actual)
- def test_infix_difference( self):
+ def test_infix_difference(self):
a = cube(2)
- b = sphere( 2)
+ b = sphere(2)
expected = '\n\ndifference() {\n\tcube(size = 2);\n\tsphere(r = 2);\n}'
- actual = scad_render( a-b)
- self.assertEqual( expected, actual)
+ actual = scad_render(a-b)
+ self.assertEqual(expected, actual)
- def test_infix_intersection( self):
+ def test_infix_intersection(self):
a = cube(2)
- b = sphere( 2)
+ b = sphere(2)
expected = '\n\nintersection() {\n\tcube(size = 2);\n\tsphere(r = 2);\n}'
- actual = scad_render( a*b)
- self.assertEqual( expected, actual)
+ actual = scad_render(a*b)
+ self.assertEqual(expected, actual)
- def test_parse_scad_callables( self):
+ def test_parse_scad_callables(self):
test_str = (""
"module hex (width=10, height=10, \n"
" flats= true, center=false){}\n"
"function righty (angle=90) = 1;\n"
- "function lefty( avar) = 2;\n"
- "module more( a=[something, other]) {}\n"
+ "function lefty(avar) = 2;\n"
+ "module more(a=[something, other]) {}\n"
"module pyramid(side=10, height=-1, square=false, centerHorizontal=true, centerVertical=false){}\n"
- "module no_comments( arg=10, //test comment\n"
+ "module no_comments(arg=10, //test comment\n"
"other_arg=2, /* some extra comments\n"
"on empty lines */\n"
"last_arg=4){}\n"
- "module float_arg( arg=1.0){}\n")
+ "module float_arg(arg=1.0){}\n")
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']}]
- actual = parse_scad_callables( test_str)
- self.assertEqual( expected, actual)
+ actual = parse_scad_callables(test_str)
+ self.assertEqual(expected, actual)
- def test_use( self):
+ def test_use(self):
include_file = self.expand_scad_path("examples/scad_to_include.scad")
- use( include_file)
+ use(include_file)
a = steps(3)
- actual = scad_render( a)
+ actual = scad_render(a)
- abs_path = a._get_include_path( include_file)
+ abs_path = a._get_include_path(include_file)
expected = "use <%s>\n\n\nsteps(howmany = 3);"%abs_path
- self.assertEqual( expected, actual)
+ self.assertEqual(expected, actual)
- def test_include( self):
+ def test_include(self):
include_file = self.expand_scad_path("examples/scad_to_include.scad")
self.assertIsNotNone(
include_file,
@@ -107,80 +107,80 @@ def test_include( self):
include(include_file)
a = steps(3)
- actual = scad_render( a)
- abs_path = a._get_include_path( include_file)
+ actual = scad_render(a)
+ abs_path = a._get_include_path(include_file)
expected = "include <%s>\n\n\nsteps(howmany = 3);"%abs_path
- self.assertEqual( expected, actual)
+ self.assertEqual(expected, actual)
- def test_extra_args_to_included_scad( self):
+ def test_extra_args_to_included_scad(self):
include_file = self.expand_scad_path("examples/scad_to_include.scad")
use(include_file)
- a = steps( 3, external_var=True)
- actual = scad_render( a)
+ a = steps(3, external_var=True)
+ actual = scad_render(a)
- abs_path = a._get_include_path( include_file)
+ abs_path = a._get_include_path(include_file)
expected = "use <%s>\n\n\nsteps(external_var = true, howmany = 3);"%abs_path
- self.assertEqual( expected, actual)
+ self.assertEqual(expected, actual)
- def test_background( self):
+ def test_background(self):
a = cube(10)
expected = '\n\n%cube(size = 10);'
- actual = scad_render( background( a))
- self.assertEqual( expected, actual)
+ actual = scad_render(background(a))
+ self.assertEqual(expected, actual)
- def test_debug( self):
+ def test_debug(self):
a = cube(10)
expected = '\n\n#cube(size = 10);'
- actual = scad_render( debug( a))
- self.assertEqual( expected, actual)
+ actual = scad_render(debug(a))
+ self.assertEqual(expected, actual)
- def test_disable( self):
+ def test_disable(self):
a = cube(10)
expected = '\n\n*cube(size = 10);'
- actual = scad_render( disable( a))
- self.assertEqual( expected, actual)
+ actual = scad_render(disable(a))
+ self.assertEqual(expected, actual)
- def test_root( self):
+ def test_root(self):
a = cube(10)
expected = '\n\n!cube(size = 10);'
- actual = scad_render( root( a))
- self.assertEqual( expected, actual)
+ actual = scad_render(root(a))
+ self.assertEqual(expected, actual)
- def test_explicit_hole( self):
- a = cube( 10, center=True) + hole()( cylinder(2, 20, center=True))
+ def test_explicit_hole(self):
+ a = cube(10, center=True) + hole()(cylinder(2, 20, center=True))
expected = '\n\ndifference(){\n\tunion() {\n\t\tcube(center = true, size = 10);\n\t}\n\t/* Holes Below*/\n\tunion(){\n\t\tcylinder(center = true, h = 20, r = 2);\n\t} /* End Holes */ \n}'
- actual = scad_render( a)
- self.assertEqual( expected, actual)
+ actual = scad_render(a)
+ self.assertEqual(expected, actual)
- def test_hole_transform_propagation( self):
+ def test_hole_transform_propagation(self):
# earlier versions of holes had problems where a hole
# that was used a couple places wouldn't propagate correctly.
# Confirm that's still happening as it's supposed to
h = hole()(
- rotate( a=90, v=[0, 1, 0])(
+ rotate(a=90, v=[0, 1, 0])(
cylinder(2, 20, center=True)
)
)
- h_vert = rotate( a=-90, v=[0, 1, 0])(
+ h_vert = rotate(a=-90, v=[0, 1, 0])(
h
)
- a = cube( 10, center=True) + h + h_vert
+ a = cube(10, center=True) + h + h_vert
expected = '\n\ndifference(){\n\tunion() {\n\t\tunion() {\n\t\t\tcube(center = true, size = 10);\n\t\t}\n\t\trotate(a = -90, v = [0, 1, 0]) {\n\t\t}\n\t}\n\t/* Holes Below*/\n\tunion(){\n\t\tunion(){\n\t\t\trotate(a = 90, v = [0, 1, 0]) {\n\t\t\t\tcylinder(center = true, h = 20, r = 2);\n\t\t\t}\n\t\t}\n\t\trotate(a = -90, v = [0, 1, 0]){\n\t\t\trotate(a = 90, v = [0, 1, 0]) {\n\t\t\t\tcylinder(center = true, h = 20, r = 2);\n\t\t\t}\n\t\t}\n\t} /* End Holes */ \n}'
- actual = scad_render( a)
- self.assertEqual( expected, actual)
+ actual = scad_render(a)
+ self.assertEqual(expected, actual)
- def test_separate_part_hole( self):
+ def test_separate_part_hole(self):
# Make two parts, a block with hole, and a cylinder that
# fits inside it. Make them separate parts, meaning
# holes will be defined at the level of the part_root node,
# not the overall node. This allows us to preserve holes as
# first class space, but then to actually fill them in with
# the parts intended to fit in them.
- b = cube( 10, center=True)
- c = cylinder( r=2, h=12, center=True)
+ b = cube(10, center=True)
+ c = cylinder(r=2, h=12, center=True)
p1 = b - hole()(c)
# Mark this cube-with-hole as a separate part from the cylinder
@@ -189,62 +189,62 @@ def test_separate_part_hole( self):
# This fits in the hole. If p1 is set as a part_root, it will all appear.
# If not, the portion of the cylinder inside the cube will not appear,
# since it would have been removed by the hole in p1
- p2 = cylinder( r=1.5, h=14, center=True)
+ p2 = cylinder(r=1.5, h=14, center=True)
a = p1 + p2
expected = '\n\nunion() {\n\tdifference(){\n\t\tdifference() {\n\t\t\tcube(center = true, size = 10);\n\t\t}\n\t\t/* Holes Below*/\n\t\tdifference(){\n\t\t\tcylinder(center = true, h = 12, r = 2);\n\t\t} /* End Holes */ \n\t}\n\tcylinder(center = true, h = 14, r = 1.5000000000);\n}'
- actual = scad_render( a)
- self.assertEqual( expected, actual)
+ actual = scad_render(a)
+ self.assertEqual(expected, actual)
- def test_scad_render_animated_file( self):
- def my_animate( _time=0):
+ def test_scad_render_animated_file(self):
+ def my_animate(_time=0):
import math
# _time will range from 0 to 1, not including 1
rads = _time * 2 * math.pi
rad = 15
- c = translate( [rad*math.cos(rads), rad*math.sin(rads)])( square( 10))
+ c = translate( [rad*math.cos(rads), rad*math.sin(rads)])(square(10))
return c
tmp = tempfile.NamedTemporaryFile()
- scad_render_animated_file( my_animate, steps=2, back_and_forth=False,
+ scad_render_animated_file(my_animate, steps=2, back_and_forth=False,
filepath=tmp.name, include_orig_code=False)
tmp.seek(0)
actual = tmp.read()
expected = b'\nif ($t >= 0.0 && $t < 0.5){ \n\ttranslate(v = [15.0000000000, 0.0000000000]) {\n\t\tsquare(size = 10);\n\t}\n}\nif ($t >= 0.5 && $t < 1.0){ \n\ttranslate(v = [-15.0000000000, 0.0000000000]) {\n\t\tsquare(size = 10);\n\t}\n}\n'
tmp.close()
- self.assertEqual( expected, actual)
+ self.assertEqual(expected, actual)
- def test_scad_render_to_file( self):
+ def test_scad_render_to_file(self):
a = circle(10)
# No header, no included original code
tmp = tempfile.NamedTemporaryFile()
- scad_render_to_file( a, filepath=tmp.name, include_orig_code=False)
+ scad_render_to_file(a, filepath=tmp.name, include_orig_code=False)
tmp.seek(0)
actual = tmp.read()
expected = b'\n\ncircle(r = 10);'
tmp.close()
- self.assertEqual( expected, actual)
+ self.assertEqual(expected, actual)
# Header
tmp = tempfile.NamedTemporaryFile()
- scad_render_to_file( a, filepath=tmp.name, include_orig_code=False,
+ scad_render_to_file(a, filepath=tmp.name, include_orig_code=False,
file_header='$fn = 24;')
tmp.seek(0)
actual = tmp.read()
expected = b'$fn = 24;\n\ncircle(r = 10);'
tmp.close()
- self.assertEqual( expected, actual)
+ self.assertEqual(expected, actual)
# TODO: test include_orig_code=True, but that would have to
# be done from a separate file, or include everything in this one
-def single_test( test_dict):
+def single_test(test_dict):
name, args, kwargs, expected = test_dict['name'], test_dict['args'], test_dict['kwargs'], test_dict['expected']
- def test( self):
+ def test(self):
call_str= name + "("
for k, v in args.items():
call_str += "%s=%s, "%(k,v)
@@ -252,18 +252,18 @@ def test( self):
call_str += "%s=%s, "%(k,v)
call_str += ')'
- scad_obj = eval( call_str)
- actual = scad_render( scad_obj)
+ scad_obj = eval(call_str)
+ actual = scad_render(scad_obj)
- self.assertEqual( expected, actual)
+ self.assertEqual(expected, actual)
return test
def generate_cases_from_templates():
for test_dict in scad_test_case_templates:
- test = single_test( test_dict)
+ test = single_test(test_dict)
test_name = "test_%(name)s"%test_dict
- setattr( TestSolidPython, test_name, test)
+ setattr(TestSolidPython, test_name, test)
if __name__ == '__main__':
diff --git a/solid/test/test_utils.py b/solid/test/test_utils.py
index c7a7bc01..72d5b7c5 100755
--- a/solid/test/test_utils.py
+++ b/solid/test/test_utils.py
@@ -11,7 +11,7 @@
from solid.test.ExpandedTestCase import DiffOutput
-tri = [Point3( 0,0,0), Point3( 10,0,0), Point3(0,10,0)]
+tri = [Point3(0,0,0), Point3(10,0,0), Point3(0,10,0)]
scad_test_cases = [
( up, [2], '\n\ntranslate(v = [0, 0, 2]);'),
( down, [2], '\n\ntranslate(v = [0, 0, -2]);'),
@@ -33,9 +33,9 @@
( euclidify, [[0,0,0]], 'Vector3(0.00, 0.00, 0.00)'),
( 'euclidify_recursive', euclidify, [[[0,0,0], [1,0,0]]], '[Vector3(0.00, 0.00, 0.00), Vector3(1.00, 0.00, 0.00)]'),
( 'euclidify_Vector', euclidify, [Vector3(0,0,0)], 'Vector3(0.00, 0.00, 0.00)'),
- ( 'euclidify_recursive_Vector', euclidify, [[Vector3( 0,0,0), Vector3( 0,0,1)]], '[Vector3(0.00, 0.00, 0.00), Vector3(0.00, 0.00, 1.00)]'),
+ ( 'euclidify_recursive_Vector', euclidify, [[Vector3(0,0,0), Vector3(0,0,1)]], '[Vector3(0.00, 0.00, 0.00), Vector3(0.00, 0.00, 1.00)]'),
( euc_to_arr, [Vector3(0,0,0)], '[0, 0, 0]'),
- ( 'euc_to_arr_recursive', euc_to_arr, [[Vector3( 0,0,0), Vector3( 0,0,1)]], '[[0, 0, 0], [0, 0, 1]]'),
+ ( 'euc_to_arr_recursive', euc_to_arr, [[Vector3(0,0,0), Vector3(0,0,1)]], '[[0, 0, 0], [0, 0, 1]]'),
( 'euc_to_arr_arr', euc_to_arr, [[0,0,0]], '[0, 0, 0]'),
( 'euc_to_arr_arr_recursive', euc_to_arr, [[[0,0,0], [1,0,0]]], '[[0, 0, 0], [1, 0, 0]]'),
( is_scad, [cube(2)], 'True'),
@@ -44,7 +44,7 @@
( 'transform_to_point_single_pt3', transform_to_point, [Point3(1,0,0), [2,2,2], [3,3,1]], 'Point3(2.71, 1.29, 2.00)'),
( 'transform_to_point_arr_arr', transform_to_point, [[[1,0,0], [0,1,0], [0,0,1]] , [2,2,2], [3,3,1]], '[Point3(2.71, 1.29, 2.00), Point3(1.84, 1.84, 2.97), Point3(1.31, 1.31, 1.77)]'),
( 'transform_to_point_pt3_arr', transform_to_point, [[Point3(1,0,0), Point3(0,1,0), Point3(0,0,1)], [2,2,2], [3,3,1]], '[Point3(2.71, 1.29, 2.00), Point3(1.84, 1.84, 2.97), Point3(1.31, 1.31, 1.77)]') ,
- ( 'transform_to_point_redundant', transform_to_point, [ [Point3( 0,0,0), Point3( 10,0,0), Point3(0,10,0)], [2,2,2], Vector3(0,0,1), Point3(0,0,0), Vector3(0,1,0), Vector3(0,0,1)], '[Point3(2.00, 2.00, 2.00), Point3(-8.00, 2.00, 2.00), Point3(2.00, 12.00, 2.00)]'),
+ ( 'transform_to_point_redundant', transform_to_point, [ [Point3(0,0,0), Point3(10,0,0), Point3(0,10,0)], [2,2,2], Vector3(0,0,1), Point3(0,0,0), Vector3(0,1,0), Vector3(0,0,1)], '[Point3(2.00, 2.00, 2.00), Point3(-8.00, 2.00, 2.00), Point3(2.00, 12.00, 2.00)]'),
( 'offset_points_inside', offset_points, [tri, 2, True], '[Point3(2.00, 2.00, 0.00), Point3(5.17, 2.00, 0.00), Point3(2.00, 5.17, 0.00)]'),
( 'offset_points_outside', offset_points, [tri, 2, False], '[Point3(-2.00, -2.00, 0.00), Point3(14.83, -2.00, 0.00), Point3(-2.00, 14.83, 0.00)]'),
( 'offset_points_open_poly', offset_points, [tri, 2, False, False], '[Point3(0.00, -2.00, 0.00), Point3(14.83, -2.00, 0.00), Point3(1.41, 11.41, 0.00)]'),
@@ -57,15 +57,15 @@ class TestSPUtils(DiffOutput):
def test_split_body_planar(self):
offset = [10, 10, 10]
- body = translate( offset)( sphere( 20))
+ body = translate(offset)(sphere(20))
body_bb = BoundingBox( [40, 40, 40], offset)
actual = []
for split_dir in [ RIGHT_VEC, FORWARD_VEC, UP_VEC]:
- actual_tuple = split_body_planar( body, body_bb, cutting_plane_normal=split_dir, cut_proportion=0.25)
- actual.append( actual_tuple)
+ actual_tuple = split_body_planar(body, body_bb, cutting_plane_normal=split_dir, cut_proportion=0.25)
+ actual.append(actual_tuple)
# Ignore the bounding box object that come back, taking only the SCAD objects
- actual = [scad_render( a) for splits in actual for a in splits[::2] ]
+ actual = [scad_render(a) for splits in actual for a in splits[::2] ]
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}',
'\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}',
@@ -74,67 +74,67 @@ def test_split_body_planar(self):
'\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}',
'\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}'
]
- self.assertEqual( actual, expected)
+ self.assertEqual(actual, expected)
- def test_fillet_2d_add( self):
+ def test_fillet_2d_add(self):
pts = [ [0,5], [5,5], [5,0], [10,0], [10,10], [0,10],]
- p = polygon( pts)
- newp = fillet_2d( euclidify(pts[0:3], Point3), orig_poly=p, fillet_rad=2, remove_material=False)
+ p = polygon(pts)
+ newp = fillet_2d(euclidify(pts[0:3], Point3), orig_poly=p, fillet_rad=2, remove_material=False)
expected = '\n\nunion() {\n\tpolygon(paths = [[0, 1, 2, 3, 4, 5]], points = [[0, 5], [5, 5], [5, 0], [10, 0], [10, 10], [0, 10]]);\n\ttranslate(v = [3.0000000000, 3.0000000000, 0.0000000000]) {\n\t\tdifference() {\n\t\t\tintersection() {\n\t\t\t\trotate(a = 358.0000000000) {\n\t\t\t\t\ttranslate(v = [-998, 0]) {\n\t\t\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trotate(a = 452.0000000000) {\n\t\t\t\t\ttranslate(v = [-998, -1000]) {\n\t\t\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcircle(r = 2);\n\t\t}\n\t}\n}'
- actual = scad_render( newp)
- self.assertEqual( expected, actual)
+ actual = scad_render(newp)
+ self.assertEqual(expected, actual)
- def test_fillet_2d_remove( self):
+ def test_fillet_2d_remove(self):
pts = tri
- poly = polygon( euc_to_arr( tri))
+ poly = polygon(euc_to_arr(tri))
- newp = fillet_2d( tri, orig_poly=poly, fillet_rad=2, remove_material=True)
+ newp = fillet_2d(tri, orig_poly=poly, fillet_rad=2, remove_material=True)
expected = '\n\ndifference() {\n\tpolygon(paths = [[0, 1, 2]], points = [[0, 0, 0], [10, 0, 0], [0, 10, 0]]);\n\ttranslate(v = [5.1715728753, 2.0000000000, 0.0000000000]) {\n\t\tdifference() {\n\t\t\tintersection() {\n\t\t\t\trotate(a = 268.0000000000) {\n\t\t\t\t\ttranslate(v = [-998, 0]) {\n\t\t\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\trotate(a = 407.0000000000) {\n\t\t\t\t\ttranslate(v = [-998, -1000]) {\n\t\t\t\t\t\tsquare(center = false, size = [1000, 1000]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tcircle(r = 2);\n\t\t}\n\t}\n}'
- actual = scad_render( newp)
+ actual = scad_render(newp)
if expected != actual:
print(''.join(difflib.unified_diff(expected, actual)))
- self.assertEqual( expected, actual)
+ self.assertEqual(expected, actual)
-def test_generator_scad( func, args, expected):
+def test_generator_scad(func, args, expected):
def test_scad(self):
scad_obj = func( *args)
- actual = scad_render( scad_obj)
- self.assertEqual( expected, actual)
+ actual = scad_render(scad_obj)
+ self.assertEqual(expected, actual)
return test_scad
-def test_generator_no_scad( func, args, expected):
- def test_no_scad( self):
- actual = str( func( *args))
- self.assertEqual( expected, actual)
+def test_generator_no_scad(func, args, expected):
+ def test_no_scad(self):
+ actual = str(func( *args))
+ self.assertEqual(expected, actual)
return test_no_scad
-def read_test_tuple( test_tuple):
- if len( test_tuple) == 3:
+def read_test_tuple(test_tuple):
+ if len(test_tuple) == 3:
# If test name not supplied, create it programmatically
func, args, expected = test_tuple
test_name = 'test_%s'%func.__name__
- elif len( test_tuple) == 4:
+ elif len(test_tuple) == 4:
test_name, func, args, expected = test_tuple
test_name = 'test_%s'%test_name
else:
- print("test_tuple has %d args :%s"%( len(test_tuple), test_tuple) )
+ print("test_tuple has %d args :%s"%(len(test_tuple), test_tuple) )
return test_name, func, args, expected
def create_tests( ):
for test_tuple in scad_test_cases:
- test_name, func, args, expected = read_test_tuple( test_tuple)
- test = test_generator_scad( func, args, expected)
- setattr( TestSPUtils, test_name, test)
+ test_name, func, args, expected = read_test_tuple(test_tuple)
+ test = test_generator_scad(func, args, expected)
+ setattr(TestSPUtils, test_name, test)
for test_tuple in other_test_cases:
- test_name, func, args, expected = read_test_tuple( test_tuple)
- test = test_generator_no_scad( func, args, expected)
- setattr( TestSPUtils, test_name, test)
+ test_name, func, args, expected = read_test_tuple(test_tuple)
+ test = test_generator_no_scad(func, args, expected)
+ setattr(TestSPUtils, test_name, test)
if __name__ == '__main__':
create_tests( )
diff --git a/solid/utils.py b/solid/utils.py
index 66d6fb5d..91a93763 100755
--- a/solid/utils.py
+++ b/solid/utils.py
@@ -11,25 +11,25 @@
X, Y, Z = (0, 1, 2)
-ORIGIN = ( 0, 0, 0)
-UP_VEC = ( 0, 0, 1)
-RIGHT_VEC = ( 1, 0, 0)
-FORWARD_VEC = ( 0, 1, 0)
-DOWN_VEC = ( 0, 0,-1)
+ORIGIN = (0, 0, 0)
+UP_VEC = (0, 0, 1)
+RIGHT_VEC = (1, 0, 0)
+FORWARD_VEC = (0, 1, 0)
+DOWN_VEC = (0, 0,-1)
LEFT_VEC = (-1, 0, 0)
-BACK_VEC = ( 0,-1, 0)
+BACK_VEC = (0,-1, 0)
# ==========
# = Colors =
# ==========
-Red = ( 1, 0, 0)
-Green = ( 0, 1, 0)
-Blue = ( 0, 0, 1)
-Cyan = ( 0, 1, 1)
-Magenta = ( 1, 0, 1)
-Yellow = ( 1, 1, 0)
-Black = ( 0, 0, 0)
-White = ( 1, 1, 1)
+Red = (1, 0, 0)
+Green = (0, 1, 0)
+Blue = (0, 0, 1)
+Cyan = (0, 1, 1)
+Magenta = (1, 0, 1)
+Yellow = (1, 1, 0)
+Black = (0, 0, 0)
+White = (1, 1, 1)
Oak = (0.65, 0.50, 0.40)
Pine = (0.85, 0.70, 0.45)
Birch = (0.90, 0.80, 0.60)
@@ -45,17 +45,17 @@
# ========================
# = Degrees <==> Radians =
# ========================
-def degrees( x_radians):
+def degrees(x_radians):
return 360.0*x_radians/TAU
-def radians( x_degrees):
+def radians(x_degrees):
return x_degrees/360.0*TAU
# ==============
# = Grid Plane =
# ==============
-def grid_plane( grid_unit=12, count=10, line_weight=0.1, plane='xz'):
+def grid_plane(grid_unit=12, count=10, line_weight=0.1, plane='xz'):
# Draws a grid of thin lines in the specified plane. Helpful for
# reference during debugging.
@@ -65,27 +65,27 @@ def grid_plane( grid_unit=12, count=10, line_weight=0.1, plane='xz'):
for i in range(-count/2, count/2+1):
if 'xz' in plane:
# xz-plane
- h = up( i*grid_unit)( cube( [ l, line_weight, line_weight], center=True))
- v = right(i*grid_unit)( cube( [ line_weight, line_weight, l], center=True))
+ h = up( i*grid_unit)(cube( [ l, line_weight, line_weight], center=True))
+ v = right(i*grid_unit)(cube( [ line_weight, line_weight, l], center=True))
t.add([h,v])
# xy plane
if 'xy' in plane:
- h = forward(i*grid_unit)( cube([ l, line_weight, line_weight], center=True))
- v = right( i*grid_unit)( cube( [ line_weight, l, line_weight], center=True))
+ h = forward(i*grid_unit)(cube([ l, line_weight, line_weight], center=True))
+ v = right( i*grid_unit)(cube( [ line_weight, l, line_weight], center=True))
t.add([h,v])
# yz plane
if 'yz' in plane:
- h = up( i*grid_unit)( cube([ line_weight, l, line_weight], center=True))
- v = forward( i*grid_unit)( cube([ line_weight, line_weight, l], center=True))
+ h = up( i*grid_unit)(cube([ line_weight, l, line_weight], center=True))
+ v = forward(i*grid_unit)(cube([ line_weight, line_weight, l], center=True))
t.add([h,v])
return t
-def distribute_in_grid( objects, max_bounding_box, rows_and_cols=None):
+def distribute_in_grid(objects, max_bounding_box, rows_and_cols=None):
# Translate each object in objects in a grid with each cell of size
# max_bounding_box.
# If
@@ -99,7 +99,7 @@ def distribute_in_grid( objects, max_bounding_box, rows_and_cols=None):
# Distributes object in a grid in the xy plane
# with objects spaced max_bounding_box apart
- if isinstance( max_bounding_box, (list, tuple)):
+ if isinstance(max_bounding_box, (list, tuple)):
x_trans, y_trans = max_bounding_box[0:2]
elif isinstance(max_bounding_box, (int, long, float, complex)):
x_trans = y_trans = max_bounding_box
@@ -116,13 +116,13 @@ def distribute_in_grid( objects, max_bounding_box, rows_and_cols=None):
if rows_and_cols:
grid_w, grid_h = rows_and_cols
else:
- grid_w = grid_h = int(ceil( sqrt(len(objects))))
+ grid_w = grid_h = int(ceil(sqrt(len(objects))))
objs_placed = 0
- for y in range( grid_h):
- for x in range( grid_w):
+ for y in range(grid_h):
+ for x in range(grid_w):
if objs_placed < len(objects):
- ret.append(translate( [x*x_trans, y*y_trans])( objects[objs_placed]))
+ ret.append(translate( [x*x_trans, y*y_trans])(objects[objs_placed]))
objs_placed += 1
else:
break
@@ -131,53 +131,53 @@ def distribute_in_grid( objects, max_bounding_box, rows_and_cols=None):
# ==============
# = Directions =
# ==============
-def up( z):
+def up(z):
return translate( [0,0,z])
-def down( z):
+def down(z):
return translate( [0,0,-z])
-def right( x):
+def right(x):
return translate( [x, 0,0])
-def left( x):
+def left(x):
return translate( [-x, 0,0])
def forward(y):
return translate( [0,y,0])
-def back( y):
+def back(y):
return translate( [0,-y,0])
# ===========================
# = Box-alignment rotations =
# ===========================
-def rot_z_to_up( obj):
+def rot_z_to_up(obj):
# NOTE: Null op
- return rotate( a=0, v=FORWARD_VEC)(obj)
+ return rotate(a=0, v=FORWARD_VEC)(obj)
-def rot_z_to_down( obj):
- return rotate( a=180, v=FORWARD_VEC)(obj)
+def rot_z_to_down(obj):
+ return rotate(a=180, v=FORWARD_VEC)(obj)
-def rot_z_to_right( obj):
- return rotate( a=90, v=FORWARD_VEC)(obj)
+def rot_z_to_right(obj):
+ return rotate(a=90, v=FORWARD_VEC)(obj)
-def rot_z_to_left( obj):
- return rotate( a=-90, v=FORWARD_VEC)(obj)
+def rot_z_to_left(obj):
+ return rotate(a=-90, v=FORWARD_VEC)(obj)
-def rot_z_to_forward( obj):
- return rotate( a=-90, v=RIGHT_VEC)(obj)
+def rot_z_to_forward(obj):
+ return rotate(a=-90, v=RIGHT_VEC)(obj)
-def rot_z_to_back( obj):
- return rotate( a=90, v=RIGHT_VEC)(obj)
+def rot_z_to_back(obj):
+ return rotate(a=90, v=RIGHT_VEC)(obj)
# ================================
# = Box-aligment and translation =
# ================================
-def box_align( obj, direction_func=up, distance=0 ):
+def box_align(obj, direction_func=up, distance=0 ):
# Given a box side (up, left, etc) and a distance,
# rotate obj (assumed to be facing up) in the
# correct direction and move it distance in that
@@ -191,63 +191,63 @@ def box_align( obj, direction_func=up, distance=0 ):
back: rot_z_to_back,
}
- assert( direction_func in trans_and_rot)
+ assert(direction_func in trans_and_rot)
rot = trans_and_rot[ direction_func]
- return direction_func( distance)( rot( obj))
+ return direction_func(distance)(rot(obj))
# =======================
# = 90-degree Rotations =
# =======================
-def rot_z_to_x( obj):
- return rotate( a=90, v=FORWARD_VEC)(obj)
+def rot_z_to_x(obj):
+ return rotate(a=90, v=FORWARD_VEC)(obj)
-def rot_z_to_neg_x( obj):
- return rotate( a=-90, v=FORWARD_VEC)(obj)
+def rot_z_to_neg_x(obj):
+ return rotate(a=-90, v=FORWARD_VEC)(obj)
-def rot_z_to_neg_y( obj):
- return rotate( a=90, v=RIGHT_VEC)(obj)
+def rot_z_to_neg_y(obj):
+ return rotate(a=90, v=RIGHT_VEC)(obj)
-def rot_z_to_y( obj):
- return rotate( a=-90, v=RIGHT_VEC)(obj)
+def rot_z_to_y(obj):
+ return rotate(a=-90, v=RIGHT_VEC)(obj)
-def rot_x_to_y( obj):
- return rotate( a=90, v=UP_VEC)(obj)
+def rot_x_to_y(obj):
+ return rotate(a=90, v=UP_VEC)(obj)
-def rot_x_to_neg_y( obj):
- return rotate( a=-90, v=UP_VEC)(obj)
+def rot_x_to_neg_y(obj):
+ return rotate(a=-90, v=UP_VEC)(obj)
# =======
# = Arc =
# =======
-def arc( rad, start_degrees, end_degrees, segments=None):
+def arc(rad, start_degrees, end_degrees, segments=None):
# Note: the circle that this arc is drawn from gets segments,
# not the arc itself. That means a quarter-circle arc will
# have segments/4 segments.
- bottom_half_square = back( rad)(square( [3*rad, 2*rad], center=True))
- top_half_square = forward( rad)( square( [3*rad, 2*rad], center=True))
+ bottom_half_square = back(rad)(square( [3*rad, 2*rad], center=True))
+ top_half_square = forward(rad)(square( [3*rad, 2*rad], center=True))
- start_shape = circle( rad, segments=segments)
+ start_shape = circle(rad, segments=segments)
if abs( (end_degrees - start_degrees)%360) <= 180:
end_angle = end_degrees - 180
ret = difference()(
start_shape,
- rotate( a=start_degrees)( bottom_half_square.copy()),
- rotate( a= end_angle)( bottom_half_square.copy())
+ rotate(a=start_degrees)( bottom_half_square.copy()),
+ rotate(a= end_angle)( bottom_half_square.copy())
)
else:
ret = intersection( )(
start_shape,
union()(
- rotate( a=start_degrees)( top_half_square.copy()),
- rotate( a=end_degrees)( bottom_half_square.copy())
+ rotate(a=start_degrees)( top_half_square.copy()),
+ rotate(a=end_degrees)( bottom_half_square.copy())
)
)
return ret
-def arc_inverted( rad, start_degrees, end_degrees, segments=None):
+def arc_inverted(rad, start_degrees, end_degrees, segments=None):
# Return the segment of an arc *outside* the circle of radius rad,
# bounded by two tangents to the circle. This is the shape
# needed for fillets.
@@ -289,13 +289,13 @@ def arc_inverted( rad, start_degrees, end_degrees, segments=None):
wide = 1000
high = 1000
- top_half_square = translate( [-(wide-rad), 0])( square([wide, high], center=False))
- bottom_half_square = translate( [-(wide-rad), -high])( square([wide, high], center=False))
+ top_half_square = translate( [-(wide-rad), 0])(square([wide, high], center=False))
+ bottom_half_square = translate( [-(wide-rad), -high])(square([wide, high], center=False))
- a = rotate( start_degrees)( top_half_square)
- b = rotate( end_degrees)( bottom_half_square)
+ a = rotate(start_degrees)(top_half_square)
+ b = rotate(end_degrees)(bottom_half_square)
- ret = (a*b) - circle( rad, segments=segments)
+ ret = (a*b) - circle(rad, segments=segments)
return ret
@@ -316,28 +316,28 @@ class BoundingBox(object):
# Basically you can use a BoundingBox to describe the extents of an object
# the moment it's created, but once you perform any CSG operation on it, it's
# more or less useless.
- def __init__( self, size, loc=None):
+ def __init__(self, size, loc=None):
loc = loc if loc else [0,0,0]
# self.w, self.h, self.d = size
# self.x, self.y, self.z = loc
- self.set_size( size)
- self.set_position( loc)
+ self.set_size(size)
+ self.set_position(loc)
- def size( self):
+ def size(self):
return [ self.w, self.h, self.d]
- def position( self):
+ def position(self):
return [ self.x, self.y, self.z]
- def set_position( self, position):
+ def set_position(self, position):
self.x, self.y, self.z = position
def set_size(self, size):
self.w, self.h, self.d = size
- def split_planar( self, cutting_plane_normal= RIGHT_VEC, cut_proportion=0.5, add_wall_thickness=0):
+ def split_planar(self, cutting_plane_normal= RIGHT_VEC, cut_proportion=0.5, add_wall_thickness=0):
cpd = {RIGHT_VEC: 0, LEFT_VEC:0, FORWARD_VEC:1, BACK_VEC:1, UP_VEC:2, DOWN_VEC:2}
- cutting_plane = cpd.get( cutting_plane_normal, 2)
+ cutting_plane = cpd.get(cutting_plane_normal, 2)
# Figure what the cutting plane offset should be
dim_center = self.position()[cutting_plane]
@@ -369,31 +369,31 @@ def split_planar( self, cutting_plane_normal= RIGHT_VEC, cut_proportion=0.5, add
loc_offset = -add_wall_thickness/2 + i*add_wall_thickness
part_loc[ cutting_plane] += loc_offset
- part_bbs.append( BoundingBox( part_size, part_loc))
+ part_bbs.append(BoundingBox(part_size, part_loc))
a_sum += part * dim
return part_bbs
- def cube( self, larger=False):
+ def cube(self, larger=False):
c_size = self.size() if not larger else [s + 2*EPSILON for s in self.size()]
- c = translate( self.position())(
- cube( c_size, center=True)
+ c = translate(self.position())(
+ cube(c_size, center=True)
)
return c
- def min( self, which_dim=None):
- min_pt = [p-s/2 for p, s in zip( self.position(), self.size())]
+ def min(self, which_dim=None):
+ min_pt = [p-s/2 for p, s in zip(self.position(), self.size())]
if which_dim:
return min_pt[ which_dim]
else:
return min_pt
- def max( self, which_dim=None):
- max_pt = [p+s/2 for p, s in zip( self.position(), self.size())]
+ def max(self, which_dim=None):
+ max_pt = [p+s/2 for p, s in zip(self.position(), self.size())]
if which_dim:
return max_pt[ which_dim]
else:
@@ -403,7 +403,7 @@ def max( self, which_dim=None):
# ===================
# = Model Splitting =
# ===================
-def split_body_planar( obj, obj_bb, cutting_plane_normal=UP_VEC, cut_proportion=0.5, dowel_holes=False, dowel_rad=4.5, hole_depth=15, add_wall_thickness=0):
+def split_body_planar(obj, obj_bb, cutting_plane_normal=UP_VEC, cut_proportion=0.5, dowel_holes=False, dowel_rad=4.5, hole_depth=15, add_wall_thickness=0):
# Split obj along the specified plane, returning two pieces and
# general bounding boxes for each.
# Note that the bounding boxes are NOT accurate to the sections,
@@ -414,7 +414,7 @@ def split_body_planar( obj, obj_bb, cutting_plane_normal=UP_VEC, cut_proportion=
# back together with short dowels.
# Find the splitting bounding boxes
- part_bbs = obj_bb.split_planar( cutting_plane_normal, cut_proportion, add_wall_thickness=add_wall_thickness)
+ part_bbs = obj_bb.split_planar(cutting_plane_normal, cut_proportion, add_wall_thickness=add_wall_thickness)
# And intersect the bounding boxes with the object itself
slices = [obj*part_bb.cube() for part_bb in part_bbs]
@@ -424,13 +424,13 @@ def split_body_planar( obj, obj_bb, cutting_plane_normal=UP_VEC, cut_proportion=
# separated by one dowel-width
if dowel_holes:
cpd = {RIGHT_VEC: 0, LEFT_VEC:0, FORWARD_VEC:1, BACK_VEC:1, UP_VEC:2, DOWN_VEC:2}
- cutting_plane = cpd.get( cutting_plane_normal, 2)
+ cutting_plane = cpd.get(cutting_plane_normal, 2)
- dowel = cylinder( r=dowel_rad, h=hole_depth*2, center=True)
+ dowel = cylinder(r=dowel_rad, h=hole_depth*2, center=True)
# rotate dowels to correct axis
if cutting_plane != 2:
rot_vec = RIGHT_VEC if cutting_plane == 1 else FORWARD_VEC
- dowel = rotate( a=90, v=rot_vec)( dowel)
+ dowel = rotate(a=90, v=rot_vec)(dowel)
cut_point = part_bbs[0].position()[ cutting_plane] + part_bbs[0].size()[ cutting_plane]/2
@@ -443,8 +443,8 @@ def split_body_planar( obj, obj_bb, cutting_plane_normal=UP_VEC, cut_proportion=
dowel_trans_b = dowel_trans_a[:]
dowel_trans_b[ separation_index] += 4*dowel_rad
- dowel_a = translate( dowel_trans_a)(dowel)
- dowel_b = translate( dowel_trans_b)(dowel)
+ dowel_a = translate(dowel_trans_a)(dowel)
+ dowel_b = translate(dowel_trans_b)(dowel)
dowels = dowel_a + dowel_b
# subtract dowels from each slice
@@ -453,10 +453,10 @@ def split_body_planar( obj, obj_bb, cutting_plane_normal=UP_VEC, cut_proportion=
slices_and_bbs = [slices[0], part_bbs[0], slices[1], part_bbs[1]]
return slices_and_bbs
-def section_cut_xz( body, y_cut_point=0):
+def section_cut_xz(body, y_cut_point=0):
big_w = 10000
d = 2
- c = forward( d/2 + y_cut_point)( cube( [big_w, d, big_w], center=True))
+ c = forward(d/2 + y_cut_point)(cube( [big_w, d, big_w], center=True))
return c * body
# =====================
@@ -467,7 +467,7 @@ def section_cut_xz( body, y_cut_point=0):
# bill_of_materials()
# to generate a report. Se examples/bom_scad.py for usage
g_parts_dict = {}
-def bom_part( description='', per_unit_price=None, currency='US$'):
+def bom_part(description='', per_unit_price=None, currency='US$'):
def wrap(f):
name = description if description else f.__name__
g_parts_dict[name] = [0, currency, per_unit_price]
@@ -533,13 +533,13 @@ def bill_of_materials_justified():
# ================
# = Bounding Box =
# ================
-def bounding_box( points):
+def bounding_box(points):
all_x = []; all_y = []; all_z = []
for p in points:
- all_x.append( p[0])
- all_y.append( p[1])
+ all_x.append(p[0])
+ all_y.append(p[1])
if len(p) > 2:
- all_z.append( p[2])
+ all_z.append(p[2])
else:
all_z.append(0)
@@ -557,28 +557,28 @@ def bounding_box( points):
}
-def screw( screw_type='m3', screw_length=16):
+def screw(screw_type='m3', screw_length=16):
dims = screw_dimensions[screw_type.lower()]
shaft_rad = dims['screw_outer_diam']/2
cap_rad = dims['cap_diam']/2
cap_height = dims['cap_height']
ret = union()(
- cylinder( shaft_rad, screw_length),
+ cylinder(shaft_rad, screw_length),
up(screw_length)(
- cylinder( cap_rad, cap_height)
+ cylinder(cap_rad, cap_height)
)
)
return ret
-def nut( screw_type='m3'):
+def nut(screw_type='m3'):
dims = screw_dimensions[screw_type.lower()]
outer_rad = dims['nut_outer_diam']
inner_rad = dims['screw_outer_diam']
ret = difference()(
- circle( outer_rad, segments=6),
- circle( inner_rad)
+ circle(outer_rad, segments=6),
+ circle(inner_rad)
)
return ret
@@ -595,7 +595,7 @@ def nut( screw_type='m3'):
import solid.patch_euclid
solid.patch_euclid.run_patch()
- def euclidify( an_obj, intended_class=Vector3):
+ def euclidify(an_obj, intended_class=Vector3):
# If an_obj is an instance of the appropriate PyEuclid class,
# return it. Otherwise, try to turn an_obj into the appropriate
# class and throw an exception on failure
@@ -606,10 +606,10 @@ def euclidify( an_obj, intended_class=Vector3):
ret = an_obj
# See if this is an array of arrays. If so, convert all sublists
- if isinstance( an_obj, (list, tuple)):
- if isinstance( an_obj[0], (list,tuple)):
+ if isinstance(an_obj, (list, tuple)):
+ if isinstance(an_obj[0], (list,tuple)):
ret = [intended_class(*p) for p in an_obj]
- elif isinstance( an_obj[0], intended_class):
+ elif isinstance(an_obj[0], intended_class):
# this array is already euclidified; return it
ret = an_obj
else:
@@ -618,7 +618,7 @@ def euclidify( an_obj, intended_class=Vector3):
except:
raise TypeError( "Object: %s ought to be PyEuclid class %s or "
"able to form one, but is not."%(an_obj, intended_class.__name__))
- elif not isinstance( an_obj, intended_class):
+ elif not isinstance(an_obj, intended_class):
try:
ret = intended_class( *an_obj)
except:
@@ -626,22 +626,22 @@ def euclidify( an_obj, intended_class=Vector3):
"able to form one, but is not."%(an_obj, intended_class.__name__))
return ret
- def euc_to_arr( euc_obj_or_list): # Inverse of euclidify()
+ def euc_to_arr(euc_obj_or_list): # Inverse of euclidify()
# Call as_arr on euc_obj_or_list or on all its members if it's a list
if hasattr(euc_obj_or_list, "as_arr"):
return euc_obj_or_list.as_arr()
- elif isinstance( euc_obj_or_list, (list, tuple)) and hasattr(euc_obj_or_list[0], 'as_arr'):
- return [euc_to_arr( p) for p in euc_obj_or_list]
+ elif isinstance(euc_obj_or_list, (list, tuple)) and hasattr(euc_obj_or_list[0], 'as_arr'):
+ return [euc_to_arr(p) for p in euc_obj_or_list]
else:
# euc_obj_or_list is neither an array-based PyEuclid object,
# nor a list of them. Assume it's a list of points or vectors,
# and return the list unchanged. We could be wrong about this, though.
return euc_obj_or_list
- def is_scad( obj):
- return isinstance( obj, openscad_object)
+ def is_scad(obj):
+ return isinstance(obj, OpenSCADObject)
- def scad_matrix( euclid_matrix4):
+ def scad_matrix(euclid_matrix4):
a = euclid_matrix4
return [[a.a, a.b, a.c, a.d],
[a.e, a.f, a.g, a.h],
@@ -653,7 +653,7 @@ def scad_matrix( euclid_matrix4):
# ==============
# = Transforms =
# ==============
- def transform_to_point( body, dest_point, dest_normal, src_point=Point3(0,0,0), src_normal=Vector3(0,1,0), src_up=Vector3(0,0,1)):
+ def transform_to_point(body, dest_point, dest_normal, src_point=Point3(0,0,0), src_normal=Vector3(0,1,0), src_up=Vector3(0,0,1)):
# Transform body to dest_point, looking at dest_normal.
# Orientation & offset can be changed by supplying the src arguments
@@ -661,30 +661,30 @@ def transform_to_point( body, dest_point, dest_normal, src_point=Point3(0,0,0),
# -- an openSCAD object
# -- a list of 3-tuples or PyEuclid Point3s
# -- a single 3-tuple or Point3
- dest_point = euclidify( dest_point, Point3)
- dest_normal = euclidify( dest_normal, Vector3)
+ dest_point = euclidify(dest_point, Point3)
+ dest_normal = euclidify(dest_normal, Vector3)
at = dest_point + dest_normal
- EUC_UP = euclidify( UP_VEC)
- EUC_FORWARD = euclidify( FORWARD_VEC)
- EUC_ORIGIN = euclidify( ORIGIN, Vector3)
+ EUC_UP = euclidify(UP_VEC)
+ EUC_FORWARD = euclidify(FORWARD_VEC)
+ EUC_ORIGIN = euclidify(ORIGIN, Vector3)
# if dest_normal and src_up are parallel, the transform collapses
# all points to dest_point. Instead, use EUC_FORWARD if needed
- if dest_normal.cross( src_up) == EUC_ORIGIN:
- if src_up.cross( EUC_UP) == EUC_ORIGIN:
+ if dest_normal.cross(src_up) == EUC_ORIGIN:
+ if src_up.cross(EUC_UP) == EUC_ORIGIN:
src_up = EUC_FORWARD
else: src_up = EUC_UP
- look_at_matrix = Matrix4.new_look_at( eye=dest_point, at=at, up=src_up )
+ look_at_matrix = Matrix4.new_look_at(eye=dest_point, at=at, up=src_up )
- if is_scad( body):
+ if is_scad(body):
# If the body being altered is a SCAD object, do the matrix mult
# in OpenSCAD
- sc_matrix = scad_matrix( look_at_matrix)
- res = multmatrix( m=sc_matrix)( body)
+ sc_matrix = scad_matrix(look_at_matrix)
+ res = multmatrix(m=sc_matrix)(body)
else:
- body = euclidify( body, Point3)
- if isinstance( body, (list, tuple)):
+ body = euclidify(body, Point3)
+ if isinstance(body, (list, tuple)):
res = [look_at_matrix * p for p in body]
else:
res = look_at_matrix * body
@@ -694,37 +694,37 @@ def transform_to_point( body, dest_point, dest_normal, src_point=Point3(0,0,0),
# ========================================
# = Vector drawing: 3D arrow from a line =
# = -------------- =======================
- def draw_segment( euc_line=None, endless=False, arrow_rad=7, vec_color=None):
+ def draw_segment(euc_line=None, endless=False, arrow_rad=7, vec_color=None):
# Draw a tradtional arrow-head vector in 3-space.
vec_arrow_rad = arrow_rad
vec_arrow_head_rad = vec_arrow_rad * 1.5
vec_arrow_head_length = vec_arrow_rad * 3
- if isinstance( euc_line, Vector3):
+ if isinstance(euc_line, Vector3):
p = Point3( *ORIGIN)
v = euc_line
- elif isinstance( euc_line, Line3):
+ elif isinstance(euc_line, Line3):
p = euc_line.p
v = -euc_line.v
- elif isinstance( euc_line, list) or isinstance( euc_line, tuple):
+ elif isinstance(euc_line, list) or isinstance(euc_line, tuple):
# TODO: This assumes p & v are PyEuclid classes.
# Really, they could as easily be two 3-tuples. Should
# check for this.
p, v = euc_line[0], euc_line[1]
shaft_length = v.magnitude() - vec_arrow_head_length
- arrow = cylinder( r= vec_arrow_rad, h = shaft_length)
- arrow += up( shaft_length )(
+ arrow = cylinder(r= vec_arrow_rad, h = shaft_length)
+ arrow += up(shaft_length )(
cylinder(r1=vec_arrow_head_rad, r2=0, h = vec_arrow_head_length)
)
if endless:
- endless_length = max( v.magnitude()*10, 200)
- arrow += cylinder( r=vec_arrow_rad/3, h = endless_length, center=True)
+ endless_length = max(v.magnitude()*10, 200)
+ arrow += cylinder(r=vec_arrow_rad/3, h = endless_length, center=True)
- arrow = transform_to_point( body=arrow, dest_point=p, dest_normal=v)
+ arrow = transform_to_point(body=arrow, dest_point=p, dest_normal=v)
if vec_color:
- arrow = color( vec_color)(arrow)
+ arrow = color(vec_color)(arrow)
return arrow
@@ -732,17 +732,17 @@ def draw_segment( euc_line=None, endless=False, arrow_rad=7, vec_color=None):
# = Offset =
# = ------ =
LEFT, RIGHT = radians(90), radians(-90)
- def offset_polygon( point_arr, offset, inside=True, closed_poly=True):
+ def offset_polygon(point_arr, offset, inside=True, closed_poly=True):
# returns a closed solidPython polygon offset by offset distance
# from the polygon described by point_arr.
- op = offset_points( point_arr, offset=offset, inside=inside, closed_poly=closed_poly)
- return polygon( euc_to_arr(op))
+ op = offset_points(point_arr, offset=offset, inside=inside, closed_poly=closed_poly)
+ return polygon(euc_to_arr(op))
- def offset_points( point_arr, offset, inside=True, closed_poly=True):
+ def offset_points(point_arr, offset, inside=True, closed_poly=True):
# Given a set of points, return a set of points offset from
# them.
# To get reasonable results, the points need to be all in a plane.
- # ( Non-planar point_arr will still return results, but what constitutes
+ # (Non-planar point_arr will still return results, but what constitutes
# 'inside' or 'outside' would be different in that situation.)
#
# What direction inside and outside lie in is determined by the first
@@ -769,10 +769,10 @@ def offset_points( point_arr, offset, inside=True, closed_poly=True):
# Using the first three points in point_arr, figure out which direction
# is inside and what plane to put the points in
- point_arr = euclidify( point_arr[:], Point3)
+ point_arr = euclidify(point_arr[:], Point3)
in_dir = _inside_direction( *point_arr[0:3])
normal = _three_point_normal( *point_arr[0:3])
- direction = in_dir if inside else _other_dir( in_dir)
+ direction = in_dir if inside else _other_dir(in_dir)
# Generate offset points for the correct direction
# for all of point_arr.
@@ -780,65 +780,65 @@ def offset_points( point_arr, offset, inside=True, closed_poly=True):
offset_pts = []
point_arr += point_arr[ 0:2] # Add first two points to the end as well
if closed_poly:
- for i in range( len(point_arr) - 1):
+ for i in range(len(point_arr) - 1):
a, b = point_arr[i:i+2]
- par_seg = _parallel_seg( a, b, normal=normal, offset=offset, direction=direction )
- segs.append( par_seg)
+ par_seg = _parallel_seg(a, b, normal=normal, offset=offset, direction=direction )
+ segs.append(par_seg)
if len(segs) > 1:
int_pt = segs[-2].intersect(segs[-1])
if int_pt:
- offset_pts.append( int_pt)
+ offset_pts.append(int_pt)
# When calculating based on a closed curve, we can't find the
# first offset point until all others have been calculated.
# Now that we've done so, put the last point back to first place
last = offset_pts[-1]
- offset_pts.insert( 0, last)
- del( offset_pts[-1])
+ offset_pts.insert(0, last)
+ del(offset_pts[-1])
else:
- for i in range( len(point_arr)-2):
+ for i in range(len(point_arr)-2):
a, b = point_arr[i:i+2]
- par_seg = _parallel_seg( a, b, normal=normal, offset=offset, direction=direction )
- segs.append( par_seg)
+ par_seg = _parallel_seg(a, b, normal=normal, offset=offset, direction=direction )
+ segs.append(par_seg)
# In an open poly, first and last points will be parallel
# to the first and last segments, not intersecting other segs
if i == 0:
- offset_pts.append( par_seg.p1)
+ offset_pts.append(par_seg.p1)
elif i == len(point_arr) - 3:
- offset_pts.append( segs[-2].p2)
+ offset_pts.append(segs[-2].p2)
else:
int_pt = segs[-2].intersect(segs[-1])
if int_pt:
- offset_pts.append( int_pt)
+ offset_pts.append(int_pt)
return offset_pts
# ==================
# = Offset helpers =
# ==================
- def _parallel_seg( p, q, offset, normal=Vector3( 0, 0, 1), direction=LEFT):
+ def _parallel_seg(p, q, offset, normal=Vector3(0, 0, 1), direction=LEFT):
# returns a PyEuclid Line3 parallel to pq, in the plane determined
# by p,normal, to the left or right of pq.
v = q - p
angle = direction
- rot_v = v.rotate_around( axis=normal, theta=angle)
- rot_v.set_length( offset)
- return Line3( p+rot_v, v )
+ rot_v = v.rotate_around(axis=normal, theta=angle)
+ rot_v.set_length(offset)
+ return Line3(p+rot_v, v )
- def _inside_direction( a, b, c, offset=10):
+ def _inside_direction(a, b, c, offset=10):
# determines which direction (LEFT, RIGHT) is 'inside' the triangle
# made by a, b, c. If ab and bc are parallel, return LEFT
- x = _three_point_normal( a, b, c)
+ x = _three_point_normal(a, b, c)
# Make two vectors (left & right) for each segment.
- l_segs = [_parallel_seg( p, q, normal=x, offset=offset, direction=LEFT) for p,q in ( (a,b), (b,c))]
- r_segs = [_parallel_seg( p, q, normal=x, offset=offset, direction=RIGHT) for p,q in ( (a,b), (b,c))]
+ l_segs = [_parallel_seg(p, q, normal=x, offset=offset, direction=LEFT) for p,q in ( (a,b), (b,c))]
+ r_segs = [_parallel_seg(p, q, normal=x, offset=offset, direction=RIGHT) for p,q in ( (a,b), (b,c))]
# Find their intersections.
- p1 = l_segs[0].intersect( l_segs[1])
- p2 = r_segs[0].intersect( r_segs[1])
+ p1 = l_segs[0].intersect(l_segs[1])
+ p2 = r_segs[0].intersect(r_segs[1])
# The only way I've figured out to determine which direction is
# 'inside' or 'outside' a joint is to calculate both inner and outer
@@ -847,30 +847,30 @@ def _inside_direction( a, b, c, offset=10):
# way to figure this out. -ETJ 21 Dec 2012
# The point that's closer to point a is the inside point.
- if a.distance( p1) <= a.distance( p2):
+ if a.distance(p1) <= a.distance(p2):
return LEFT
else:
return RIGHT
- def _other_dir( left_or_right):
+ def _other_dir(left_or_right):
if left_or_right == LEFT:
return RIGHT
else:
return LEFT
- def _three_point_normal( a, b, c):
+ def _three_point_normal(a, b, c):
ab = b - a
bc = c - b
- seg_ab = Line3( a, ab)
- seg_bc = Line3( b, bc)
- x = seg_ab.v.cross( seg_bc.v)
+ seg_ab = Line3(a, ab)
+ seg_bc = Line3(b, bc)
+ x = seg_ab.v.cross(seg_bc.v)
return x
# =============
# = 2D Fillet =
# =============
- def _widen_angle_for_fillet( start_degrees, end_degrees):
+ def _widen_angle_for_fillet(start_degrees, end_degrees):
# Fix start/end degrees as needed; find a way to make an acute angle
if end_degrees < start_degrees:
end_degrees += 360
@@ -881,7 +881,7 @@ def _widen_angle_for_fillet( start_degrees, end_degrees):
epsilon_degrees = 2
return start_degrees - epsilon_degrees, end_degrees + epsilon_degrees
- def fillet_2d( three_point_sets, orig_poly, fillet_rad, remove_material=True):
+ def fillet_2d(three_point_sets, orig_poly, fillet_rad, remove_material=True):
# NOTE: three_point_sets must be a list of sets of three points
# (i.e., a list of 3-tuples of points), even if only one fillet is being done:
# e.g. [[a, b, c]]
@@ -892,7 +892,7 @@ def fillet_2d( three_point_sets, orig_poly, fillet_rad, remove_material=True):
# Note that if rad is greater than a.distance(b) or c.distance(b), for a
# 90-degree corner, the returned shape will include a jagged edge.
- # TODO: use fillet_rad = min( fillet_rad, a.distance(b), c.distance(b))
+ # TODO: use fillet_rad = min(fillet_rad, a.distance(b), c.distance(b))
# If a shape is being filleted in several places, it is FAR faster
# to add/ remove its set of shapes all at once rather than
@@ -904,7 +904,7 @@ def fillet_2d( three_point_sets, orig_poly, fillet_rad, remove_material=True):
# NOTE that if material is being added (fillets) or removed (rounds)
# each must be called separately.
- if len( three_point_sets) == 3 and isinstance( three_point_sets[0], (Vector2, Vector3)):
+ if len(three_point_sets) == 3 and isinstance(three_point_sets[0], (Vector2, Vector3)):
three_point_sets = [three_point_sets]
arc_objs = []
@@ -912,39 +912,39 @@ def fillet_2d( three_point_sets, orig_poly, fillet_rad, remove_material=True):
assert len(three_points) in (2,3)
# make two vectors out of the three points passed in
- a, b, c = euclidify( three_points, Point3)
+ a, b, c = euclidify(three_points, Point3)
# Find the center of the arc we'll have to make
offset = offset_points( [a, b, c], offset=fillet_rad, inside=True)
center_pt = offset[1]
- a2, b2, c2, cp2 = [Point2( p.x, p.y) for p in (a,b,c, center_pt)]
+ a2, b2, c2, cp2 = [Point2(p.x, p.y) for p in (a,b,c, center_pt)]
- a2b2 = LineSegment2( a2, b2)
- c2b2 = LineSegment2( c2, b2)
+ a2b2 = LineSegment2(a2, b2)
+ c2b2 = LineSegment2(c2, b2)
# Find the point on each segment where the arc starts; Point2.connect()
# returns a segment with two points; Take the one that's not the center
- afs = cp2.connect( a2b2)
- cfs = cp2.connect( c2b2)
+ afs = cp2.connect(a2b2)
+ cfs = cp2.connect(c2b2)
afp, cfp = [seg.p1 if seg.p1 != cp2 else seg.p2 for seg in (afs, cfs)]
- a_degs, c_degs = [ (degrees(math.atan2( seg.v.y, seg.v.x)))%360 for seg in (afs, cfs)]
+ a_degs, c_degs = [ (degrees(math.atan2(seg.v.y, seg.v.x)))%360 for seg in (afs, cfs)]
start_degs = a_degs
end_degs = c_degs
# Widen start_degs and end_degs slightly so they overlap the areas
# they're supposed to join/ remove.
- start_degs, end_degs = _widen_angle_for_fillet( start_degs, end_degs)
+ start_degs, end_degs = _widen_angle_for_fillet(start_degs, end_degs)
- arc_obj = translate( center_pt.as_arr() )(
- arc_inverted( rad=fillet_rad, start_degrees=start_degs, end_degrees=end_degs)
+ arc_obj = translate(center_pt.as_arr() )(
+ arc_inverted(rad=fillet_rad, start_degrees=start_degs, end_degrees=end_degs)
)
- arc_objs.append( arc_obj)
+ arc_objs.append(arc_obj)
if remove_material:
poly = orig_poly - arc_objs
@@ -957,12 +957,12 @@ def fillet_2d( three_point_sets, orig_poly, fillet_rad, remove_material=True):
# ==========================
# = Extrusion along a path =
# = ---------------------- =
- def extrude_along_path( shape_pts, path_pts, scale_factors=None): # Possible: twist
+ def extrude_along_path(shape_pts, path_pts, scale_factors=None): # Possible: twist
# Extrude the convex curve defined by shape_pts along path_pts.
# -- For predictable results, shape_pts must be planar, convex, and lie
# in the XY plane centered around the origin.
#
- # -- len( scale_factors) should equal len( path_pts). If not present, scale
+ # -- len(scale_factors) should equal len(path_pts). If not present, scale
# will be assumed to be 1.0 for each point in path_pts
# -- Future additions might include corner styles (sharp, flattened, round)
# or a twist factor
@@ -973,12 +973,12 @@ def extrude_along_path( shape_pts, path_pts, scale_factors=None): # Possible: tw
scale_factors = [1.0] * len(path_pts)
# Make sure we've got Euclid Point3's for all elements
- shape_pts = euclidify( shape_pts, Point3)
- path_pts = euclidify( path_pts, Point3)
+ shape_pts = euclidify(shape_pts, Point3)
+ path_pts = euclidify(path_pts, Point3)
src_up = Vector3( *UP_VEC)
- for which_loop in range( len( path_pts) ):
+ for which_loop in range(len(path_pts) ):
path_pt = path_pts[which_loop]
scale = scale_factors[which_loop]
@@ -992,7 +992,7 @@ def extrude_along_path( shape_pts, path_pts, scale_factors=None): # Possible: tw
tangent = v_prev + v_next
elif which_loop == 0:
tangent = path_pts[which_loop+1] - path_pt
- elif which_loop == len( path_pts) - 1:
+ elif which_loop == len(path_pts) - 1:
tangent = path_pt - path_pts[ which_loop -1]
# Scale points
@@ -1005,7 +1005,7 @@ def extrude_along_path( shape_pts, path_pts, scale_factors=None): # Possible: tw
# Rotate & translate
- this_loop = transform_to_point( this_loop, dest_point=path_pt, dest_normal=tangent, src_up=src_up)
+ this_loop = transform_to_point(this_loop, dest_point=path_pt, dest_normal=tangent, src_up=src_up)
# Add the transformed points to our final list
polyhedron_pts += this_loop
@@ -1014,7 +1014,7 @@ def extrude_along_path( shape_pts, path_pts, scale_factors=None): # Possible: tw
segment_start = which_loop*shape_pt_count
segment_end = segment_start + shape_pt_count - 1
if which_loop < len(path_pts) - 1:
- for i in range( segment_start, segment_end):
+ for i in range(segment_start, segment_end):
facet_indices.append( [i, i+shape_pt_count, i+1])
facet_indices.append( [i+1, i+shape_pt_count, i+shape_pt_count+1])
facet_indices.append( [segment_start, segment_end, segment_end + shape_pt_count])
@@ -1024,13 +1024,13 @@ def extrude_along_path( shape_pts, path_pts, scale_factors=None): # Possible: tw
for i in range(1, shape_pt_count - 1):
facet_indices.append( [0, i, i+1])
- # And the end ( could be rolled into the earlier loop)
+ # And the end (could be rolled into the earlier loop)
# FIXME: concave cross-sections will cause this end-capping algorithm to fail
- end_cap_base = len( polyhedron_pts) - shape_pt_count
- for i in range( end_cap_base + 1, len(polyhedron_pts) -1):
+ end_cap_base = len(polyhedron_pts) - shape_pt_count
+ for i in range(end_cap_base + 1, len(polyhedron_pts) -1):
facet_indices.append( [ end_cap_base, i+1, i])
- return polyhedron( points = euc_to_arr(polyhedron_pts), faces=facet_indices)
+ return polyhedron(points = euc_to_arr(polyhedron_pts), faces=facet_indices)
except Exception as e:
@@ -1099,7 +1099,7 @@ def frange(*args):
# =====================
# = D e b u g g i n g =
# =====================
-def obj_tree_str( sp_obj, vars_to_print=None):
+def obj_tree_str(sp_obj, vars_to_print=None):
# For debugging. This prints a string of all of an object's
# children, with whatever attributes are specified in vars_to_print
@@ -1111,15 +1111,15 @@ def obj_tree_str( sp_obj, vars_to_print=None):
parent_sign = "\nL " if sp_obj.parent else "\n* "
# Print object
- s = parent_sign + str( sp_obj) + "\t"
+ s = parent_sign + str(sp_obj) + "\t"
# Extra desired fields
for v in vars_to_print:
- if hasattr( sp_obj, v):
- s += "%s: %s\t"%( v, getattr(sp_obj, v))
+ if hasattr(sp_obj, v):
+ s += "%s: %s\t"%(v, getattr(sp_obj, v))
# Add all children
for c in sp_obj.children:
- s += indent( obj_tree_str(c, vars_to_print))
+ s += indent(obj_tree_str(c, vars_to_print))
return s