diff --git a/.gitignore b/.gitignore index b9b09fd..9bf99e6 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,4 @@ target/ # Created by nosetests cover/ +example_module.scad diff --git a/example/example.stl b/example/example.stl new file mode 100644 index 0000000..4f91b42 --- /dev/null +++ b/example/example.stl @@ -0,0 +1,814 @@ +solid OpenSCAD_Model + facet normal -0 -0 -1 + outer loop + vertex 9.78148 2.07912 0 + vertex 10 0 0 + vertex 9.13545 4.06737 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex 9.13545 4.06737 0 + vertex 6.69131 7.43145 0 + vertex 8.09017 5.87785 0 + endloop + endfacet + facet normal -0 0 -1 + outer loop + vertex 10 0 0 + vertex 9.78148 -2.07912 0 + vertex 9.13545 4.06737 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex 9.13545 4.06737 0 + vertex 3.09017 9.51057 0 + vertex 6.69131 7.43145 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex 6.69131 7.43145 0 + vertex 3.09017 9.51057 0 + vertex 5 8.66025 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -8.09017 5.87785 0 + vertex -9.13545 -4.06737 0 + vertex -10 5.66554e-15 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex 3.09017 9.51057 0 + vertex -1.04528 9.94522 0 + vertex 1.04528 9.94522 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -6.69131 7.43145 0 + vertex -5 8.66025 0 + vertex -1.04528 9.94522 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -1.04528 9.94522 0 + vertex -5 8.66025 0 + vertex -3.09017 9.51057 0 + endloop + endfacet + facet normal -0 0 -1 + outer loop + vertex 3.09017 9.51057 0 + vertex -6.69131 7.43145 0 + vertex -1.04528 9.94522 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -10 5.66554e-15 0 + vertex -9.13545 -4.06737 0 + vertex -9.78148 -2.07912 0 + endloop + endfacet + facet normal 0 -0 -1 + outer loop + vertex -8.09017 5.87785 0 + vertex -6.69131 7.43145 0 + vertex -9.13545 -4.06737 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -8.09017 5.87785 0 + vertex -9.78148 2.07912 0 + vertex -9.13545 4.06737 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -8.09017 5.87785 0 + vertex -10 5.66554e-15 0 + vertex -9.78148 2.07912 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -9.13545 -4.06737 0 + vertex -6.69131 7.43145 0 + vertex -3.09017 -9.51057 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -6.69131 -7.43145 0 + vertex -9.13545 -4.06737 0 + vertex -3.09017 -9.51057 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -3.09017 -9.51057 0 + vertex -6.69131 7.43145 0 + vertex 3.09017 9.51057 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -9.13545 -4.06737 0 + vertex -6.69131 -7.43145 0 + vertex -8.09017 -5.87785 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -3.09017 -9.51057 0 + vertex -5 -8.66025 0 + vertex -6.69131 -7.43145 0 + endloop + endfacet + facet normal -0 0 -1 + outer loop + vertex 9.13545 4.06737 0 + vertex -3.09017 -9.51057 0 + vertex 3.09017 9.51057 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex 9.13545 4.06737 0 + vertex 1.04528 -9.94522 0 + vertex -3.09017 -9.51057 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex -3.09017 -9.51057 0 + vertex 1.04528 -9.94522 0 + vertex -1.04528 -9.94522 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex 9.13545 4.06737 0 + vertex 5 -8.66025 0 + vertex 1.04528 -9.94522 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex 1.04528 -9.94522 0 + vertex 5 -8.66025 0 + vertex 3.09017 -9.51057 0 + endloop + endfacet + facet normal 0 -0 -1 + outer loop + vertex 9.13545 4.06737 0 + vertex 9.78148 -2.07912 0 + vertex 5 -8.66025 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex 5 -8.66025 0 + vertex 9.78148 -2.07912 0 + vertex 6.69131 -7.43145 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex 6.69131 -7.43145 0 + vertex 9.78148 -2.07912 0 + vertex 8.09017 -5.87785 0 + endloop + endfacet + facet normal 0 0 -1 + outer loop + vertex 8.09017 -5.87785 0 + vertex 9.78148 -2.07912 0 + vertex 9.13545 -4.06737 0 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex 9.13545 4.06737 10 + vertex 10 0 10 + vertex 9.78148 2.07912 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex 8.09017 5.87785 10 + vertex 6.69131 7.43145 10 + vertex 9.13545 4.06737 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex 9.13545 4.06737 10 + vertex 9.78148 -2.07912 10 + vertex 10 0 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex 6.69131 7.43145 10 + vertex 3.09017 9.51057 10 + vertex 9.13545 4.06737 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex 5 8.66025 10 + vertex 3.09017 9.51057 10 + vertex 6.69131 7.43145 10 + endloop + endfacet + facet normal -0 0 1 + outer loop + vertex -10 5.66554e-15 10 + vertex -9.13545 -4.06737 10 + vertex -8.09017 5.87785 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex 1.04528 9.94522 10 + vertex -1.04528 9.94522 10 + vertex 3.09017 9.51057 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex -1.04528 9.94522 10 + vertex -5 8.66025 10 + vertex -6.69131 7.43145 10 + endloop + endfacet + facet normal -0 0 1 + outer loop + vertex -3.09017 9.51057 10 + vertex -5 8.66025 10 + vertex -1.04528 9.94522 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex -1.04528 9.94522 10 + vertex -6.69131 7.43145 10 + vertex 3.09017 9.51057 10 + endloop + endfacet + facet normal -0 -0 1 + outer loop + vertex -9.78148 -2.07912 10 + vertex -9.13545 -4.06737 10 + vertex -10 5.66554e-15 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex -9.13545 -4.06737 10 + vertex -6.69131 7.43145 10 + vertex -8.09017 5.87785 10 + endloop + endfacet + facet normal -0 0 1 + outer loop + vertex -9.13545 4.06737 10 + vertex -9.78148 2.07912 10 + vertex -8.09017 5.87785 10 + endloop + endfacet + facet normal -0 0 1 + outer loop + vertex -9.78148 2.07912 10 + vertex -10 5.66554e-15 10 + vertex -8.09017 5.87785 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex -3.09017 -9.51057 10 + vertex -6.69131 7.43145 10 + vertex -9.13545 -4.06737 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex -3.09017 -9.51057 10 + vertex -9.13545 -4.06737 10 + vertex -6.69131 -7.43145 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex 3.09017 9.51057 10 + vertex -6.69131 7.43145 10 + vertex -3.09017 -9.51057 10 + endloop + endfacet + facet normal -0 -0 1 + outer loop + vertex -8.09017 -5.87785 10 + vertex -6.69131 -7.43145 10 + vertex -9.13545 -4.06737 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex -6.69131 -7.43145 10 + vertex -5 -8.66025 10 + vertex -3.09017 -9.51057 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex 3.09017 9.51057 10 + vertex -3.09017 -9.51057 10 + vertex 9.13545 4.06737 10 + endloop + endfacet + facet normal -0 0 1 + outer loop + vertex -3.09017 -9.51057 10 + vertex 1.04528 -9.94522 10 + vertex 9.13545 4.06737 10 + endloop + endfacet + facet normal 0 -0 1 + outer loop + vertex -1.04528 -9.94522 10 + vertex 1.04528 -9.94522 10 + vertex -3.09017 -9.51057 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex 1.04528 -9.94522 10 + vertex 5 -8.66025 10 + vertex 9.13545 4.06737 10 + endloop + endfacet + facet normal 0 -0 1 + outer loop + vertex 3.09017 -9.51057 10 + vertex 5 -8.66025 10 + vertex 1.04528 -9.94522 10 + endloop + endfacet + facet normal 0 0 1 + outer loop + vertex 5 -8.66025 10 + vertex 9.78148 -2.07912 10 + vertex 9.13545 4.06737 10 + endloop + endfacet + facet normal 0 -0 1 + outer loop + vertex 6.69131 -7.43145 10 + vertex 9.78148 -2.07912 10 + vertex 5 -8.66025 10 + endloop + endfacet + facet normal 0 -0 1 + outer loop + vertex 8.09017 -5.87785 10 + vertex 9.78148 -2.07912 10 + vertex 6.69131 -7.43145 10 + endloop + endfacet + facet normal 0 -0 1 + outer loop + vertex 9.13545 -4.06737 10 + vertex 9.78148 -2.07912 10 + vertex 8.09017 -5.87785 10 + endloop + endfacet + facet normal 0.994522 0.104528 0 + outer loop + vertex 9.78148 2.07912 0 + vertex 10 0 10 + vertex 10 0 0 + endloop + endfacet + facet normal 0.994522 0.104528 -0 + outer loop + vertex 9.78148 2.07912 0 + vertex 9.78148 2.07912 10 + vertex 10 0 10 + endloop + endfacet + facet normal 0.951057 0.309017 0 + outer loop + vertex 9.13545 4.06737 0 + vertex 9.78148 2.07912 10 + vertex 9.78148 2.07912 0 + endloop + endfacet + facet normal 0.951057 0.309017 -0 + outer loop + vertex 9.13545 4.06737 0 + vertex 9.13545 4.06737 10 + vertex 9.78148 2.07912 10 + endloop + endfacet + facet normal 0.866025 0.5 0 + outer loop + vertex 8.09017 5.87785 0 + vertex 9.13545 4.06737 10 + vertex 9.13545 4.06737 0 + endloop + endfacet + facet normal 0.866025 0.5 -0 + outer loop + vertex 8.09017 5.87785 0 + vertex 8.09017 5.87785 10 + vertex 9.13545 4.06737 10 + endloop + endfacet + facet normal 0.743145 0.669131 0 + outer loop + vertex 6.69131 7.43145 0 + vertex 8.09017 5.87785 10 + vertex 8.09017 5.87785 0 + endloop + endfacet + facet normal 0.743145 0.669131 -0 + outer loop + vertex 6.69131 7.43145 0 + vertex 6.69131 7.43145 10 + vertex 8.09017 5.87785 10 + endloop + endfacet + facet normal 0.587785 0.809017 0 + outer loop + vertex 5 8.66025 0 + vertex 6.69131 7.43145 10 + vertex 6.69131 7.43145 0 + endloop + endfacet + facet normal 0.587785 0.809017 -0 + outer loop + vertex 5 8.66025 0 + vertex 5 8.66025 10 + vertex 6.69131 7.43145 10 + endloop + endfacet + facet normal 0.406737 0.913545 0 + outer loop + vertex 3.09017 9.51057 0 + vertex 5 8.66025 10 + vertex 5 8.66025 0 + endloop + endfacet + facet normal 0.406737 0.913545 -0 + outer loop + vertex 3.09017 9.51057 0 + vertex 3.09017 9.51057 10 + vertex 5 8.66025 10 + endloop + endfacet + facet normal 0.207912 0.978148 0 + outer loop + vertex 1.04528 9.94522 0 + vertex 3.09017 9.51057 10 + vertex 3.09017 9.51057 0 + endloop + endfacet + facet normal 0.207912 0.978148 -0 + outer loop + vertex 1.04528 9.94522 0 + vertex 1.04528 9.94522 10 + vertex 3.09017 9.51057 10 + endloop + endfacet + facet normal 0 1 0 + outer loop + vertex -1.04528 9.94522 0 + vertex 1.04528 9.94522 10 + vertex 1.04528 9.94522 0 + endloop + endfacet + facet normal 0 1 0 + outer loop + vertex -1.04528 9.94522 0 + vertex -1.04528 9.94522 10 + vertex 1.04528 9.94522 10 + endloop + endfacet + facet normal -0.207912 0.978148 0 + outer loop + vertex -3.09017 9.51057 0 + vertex -1.04528 9.94522 10 + vertex -1.04528 9.94522 0 + endloop + endfacet + facet normal -0.207912 0.978148 0 + outer loop + vertex -3.09017 9.51057 0 + vertex -3.09017 9.51057 10 + vertex -1.04528 9.94522 10 + endloop + endfacet + facet normal -0.406737 0.913545 0 + outer loop + vertex -5 8.66025 0 + vertex -3.09017 9.51057 10 + vertex -3.09017 9.51057 0 + endloop + endfacet + facet normal -0.406737 0.913545 0 + outer loop + vertex -5 8.66025 0 + vertex -5 8.66025 10 + vertex -3.09017 9.51057 10 + endloop + endfacet + facet normal -0.587785 0.809017 0 + outer loop + vertex -6.69131 7.43145 0 + vertex -5 8.66025 10 + vertex -5 8.66025 0 + endloop + endfacet + facet normal -0.587785 0.809017 0 + outer loop + vertex -6.69131 7.43145 0 + vertex -6.69131 7.43145 10 + vertex -5 8.66025 10 + endloop + endfacet + facet normal -0.743145 0.669131 0 + outer loop + vertex -8.09017 5.87785 0 + vertex -6.69131 7.43145 10 + vertex -6.69131 7.43145 0 + endloop + endfacet + facet normal -0.743145 0.669131 0 + outer loop + vertex -8.09017 5.87785 0 + vertex -8.09017 5.87785 10 + vertex -6.69131 7.43145 10 + endloop + endfacet + facet normal -0.866025 0.5 0 + outer loop + vertex -9.13545 4.06737 0 + vertex -8.09017 5.87785 10 + vertex -8.09017 5.87785 0 + endloop + endfacet + facet normal -0.866025 0.5 0 + outer loop + vertex -9.13545 4.06737 0 + vertex -9.13545 4.06737 10 + vertex -8.09017 5.87785 10 + endloop + endfacet + facet normal -0.951057 0.309017 0 + outer loop + vertex -9.78148 2.07912 0 + vertex -9.13545 4.06737 10 + vertex -9.13545 4.06737 0 + endloop + endfacet + facet normal -0.951057 0.309017 0 + outer loop + vertex -9.78148 2.07912 0 + vertex -9.78148 2.07912 10 + vertex -9.13545 4.06737 10 + endloop + endfacet + facet normal -0.994522 0.104528 0 + outer loop + vertex -10 5.66554e-15 0 + vertex -9.78148 2.07912 10 + vertex -9.78148 2.07912 0 + endloop + endfacet + facet normal -0.994522 0.104528 0 + outer loop + vertex -10 5.66554e-15 0 + vertex -10 5.66554e-15 10 + vertex -9.78148 2.07912 10 + endloop + endfacet + facet normal -0.994522 -0.104528 0 + outer loop + vertex -9.78148 -2.07912 0 + vertex -10 5.66554e-15 10 + vertex -10 5.66554e-15 0 + endloop + endfacet + facet normal -0.994522 -0.104528 0 + outer loop + vertex -9.78148 -2.07912 0 + vertex -9.78148 -2.07912 10 + vertex -10 5.66554e-15 10 + endloop + endfacet + facet normal -0.951057 -0.309017 0 + outer loop + vertex -9.13545 -4.06737 0 + vertex -9.78148 -2.07912 10 + vertex -9.78148 -2.07912 0 + endloop + endfacet + facet normal -0.951057 -0.309017 0 + outer loop + vertex -9.13545 -4.06737 0 + vertex -9.13545 -4.06737 10 + vertex -9.78148 -2.07912 10 + endloop + endfacet + facet normal -0.866025 -0.5 0 + outer loop + vertex -8.09017 -5.87785 0 + vertex -9.13545 -4.06737 10 + vertex -9.13545 -4.06737 0 + endloop + endfacet + facet normal -0.866025 -0.5 0 + outer loop + vertex -8.09017 -5.87785 0 + vertex -8.09017 -5.87785 10 + vertex -9.13545 -4.06737 10 + endloop + endfacet + facet normal -0.743145 -0.669131 0 + outer loop + vertex -6.69131 -7.43145 0 + vertex -8.09017 -5.87785 10 + vertex -8.09017 -5.87785 0 + endloop + endfacet + facet normal -0.743145 -0.669131 0 + outer loop + vertex -6.69131 -7.43145 0 + vertex -6.69131 -7.43145 10 + vertex -8.09017 -5.87785 10 + endloop + endfacet + facet normal -0.587785 -0.809017 0 + outer loop + vertex -5 -8.66025 0 + vertex -6.69131 -7.43145 10 + vertex -6.69131 -7.43145 0 + endloop + endfacet + facet normal -0.587785 -0.809017 0 + outer loop + vertex -5 -8.66025 0 + vertex -5 -8.66025 10 + vertex -6.69131 -7.43145 10 + endloop + endfacet + facet normal -0.406737 -0.913545 0 + outer loop + vertex -3.09017 -9.51057 0 + vertex -5 -8.66025 10 + vertex -5 -8.66025 0 + endloop + endfacet + facet normal -0.406737 -0.913545 0 + outer loop + vertex -3.09017 -9.51057 0 + vertex -3.09017 -9.51057 10 + vertex -5 -8.66025 10 + endloop + endfacet + facet normal -0.207912 -0.978148 0 + outer loop + vertex -1.04528 -9.94522 0 + vertex -3.09017 -9.51057 10 + vertex -3.09017 -9.51057 0 + endloop + endfacet + facet normal -0.207912 -0.978148 0 + outer loop + vertex -1.04528 -9.94522 0 + vertex -1.04528 -9.94522 10 + vertex -3.09017 -9.51057 10 + endloop + endfacet + facet normal 0 -1 0 + outer loop + vertex 1.04528 -9.94522 0 + vertex -1.04528 -9.94522 10 + vertex -1.04528 -9.94522 0 + endloop + endfacet + facet normal 0 -1 0 + outer loop + vertex 1.04528 -9.94522 0 + vertex 1.04528 -9.94522 10 + vertex -1.04528 -9.94522 10 + endloop + endfacet + facet normal 0.207912 -0.978148 0 + outer loop + vertex 3.09017 -9.51057 0 + vertex 1.04528 -9.94522 10 + vertex 1.04528 -9.94522 0 + endloop + endfacet + facet normal 0.207912 -0.978148 0 + outer loop + vertex 3.09017 -9.51057 0 + vertex 3.09017 -9.51057 10 + vertex 1.04528 -9.94522 10 + endloop + endfacet + facet normal 0.406737 -0.913545 0 + outer loop + vertex 5 -8.66025 0 + vertex 3.09017 -9.51057 10 + vertex 3.09017 -9.51057 0 + endloop + endfacet + facet normal 0.406737 -0.913545 0 + outer loop + vertex 5 -8.66025 0 + vertex 5 -8.66025 10 + vertex 3.09017 -9.51057 10 + endloop + endfacet + facet normal 0.587785 -0.809017 0 + outer loop + vertex 6.69131 -7.43145 0 + vertex 5 -8.66025 10 + vertex 5 -8.66025 0 + endloop + endfacet + facet normal 0.587785 -0.809017 0 + outer loop + vertex 6.69131 -7.43145 0 + vertex 6.69131 -7.43145 10 + vertex 5 -8.66025 10 + endloop + endfacet + facet normal 0.743145 -0.669131 0 + outer loop + vertex 8.09017 -5.87785 0 + vertex 6.69131 -7.43145 10 + vertex 6.69131 -7.43145 0 + endloop + endfacet + facet normal 0.743145 -0.669131 0 + outer loop + vertex 8.09017 -5.87785 0 + vertex 8.09017 -5.87785 10 + vertex 6.69131 -7.43145 10 + endloop + endfacet + facet normal 0.866025 -0.5 0 + outer loop + vertex 9.13545 -4.06737 0 + vertex 8.09017 -5.87785 10 + vertex 8.09017 -5.87785 0 + endloop + endfacet + facet normal 0.866025 -0.5 0 + outer loop + vertex 9.13545 -4.06737 0 + vertex 9.13545 -4.06737 10 + vertex 8.09017 -5.87785 10 + endloop + endfacet + facet normal 0.951057 -0.309017 0 + outer loop + vertex 9.78148 -2.07912 0 + vertex 9.13545 -4.06737 10 + vertex 9.13545 -4.06737 0 + endloop + endfacet + facet normal 0.951057 -0.309017 0 + outer loop + vertex 9.78148 -2.07912 0 + vertex 9.78148 -2.07912 10 + vertex 9.13545 -4.06737 10 + endloop + endfacet + facet normal 0.994522 -0.104528 0 + outer loop + vertex 10 0 0 + vertex 9.78148 -2.07912 10 + vertex 9.78148 -2.07912 0 + endloop + endfacet + facet normal 0.994522 -0.104528 0 + outer loop + vertex 10 0 0 + vertex 10 0 10 + vertex 9.78148 -2.07912 10 + endloop + endfacet +endsolid OpenSCAD_Model diff --git a/openpyscad/__init__.py b/openpyscad/__init__.py index 0e51a8c..08386e0 100644 --- a/openpyscad/__init__.py +++ b/openpyscad/__init__.py @@ -7,6 +7,7 @@ from .shapes_2d import * from .boolean import * from .transformations import * +from .custom2dshapes import Custom2dShapes __name__ = "OpenPySCAD" __version__ = "0.2.0" diff --git a/openpyscad/base.py b/openpyscad/base.py index 0478212..c7d6455 100644 --- a/openpyscad/base.py +++ b/openpyscad/base.py @@ -3,10 +3,12 @@ # Python 2 and 3: from six import with_metaclass +import os + from .modifiers import ModifierMixin -__all__ = ["Empty", "BaseObject"] +__all__ = ["Empty", "BaseObject", "Scad", "Import"] INDENT = " " @@ -30,8 +32,10 @@ class MetaObject(type): "linear_extrude": ("linear_extrude", ("height", "center", "convexity", "twist", "slices", "scale"), True), + "rotate_extrude": ("rotate_extrude", ("angle", "convexity", + "_fn"), True), # 2D - "circle": ("circle", ("r", "d"), False), + "circle": ("circle", ("r", "d", "_fn"), False), "square": ("square", ("size", "center"), False), "polygon": ("polygon", ("points", "paths", "convexity"), False), "text": ("text", @@ -39,13 +43,16 @@ class MetaObject(type): "direction", "language", "script", "_fn"), False), # 3D - "sphere": ("sphere", ("r", "d", "_fa", "_fs", "_fn"), False), + "sphere": ("sphere", ("r", "d", "center", "_fa", "_fs", "_fn"), False), "cube": ("cube", ("size", "center"), False), "cylinder": ("cylinder", ("h", "r", "r1", "r2", "d", "d1", "d2", "center", "_fa", "_fs", "_fn"), False ), + "scad": ("scad", ("scadfile", "version"), False), + "import": ("import", ("file", "convexity"), False), + "surface": ("surface", ("file", "center", "invert", "convexity"), False), "polyhedron": ("polyhedron", ("points", "triangles", "faces", "convexity"), False) @@ -66,6 +73,7 @@ class _BaseObject(with_metaclass(MetaObject, ModifierMixin, object)): def __init__(self, *args, **kwargs): super(_BaseObject, self).__init__() + self.modules = list() for k, v in kwargs.items(): if hasattr(self.__class__, k): setattr(self, k, v) @@ -89,7 +97,7 @@ def _retrieve_value(self, name): return "{}".format(val) - def _get_params(self): + def _get_params(self, fp=None): valid_keys = list(filter(lambda x: getattr(self, x) is not None, self._properties)) def is_no_keyword_args(arg_name): @@ -106,6 +114,35 @@ def convert_special_args(arg_name): return "$" + arg_name[1:] return arg_name + def _get_attr(self, x, fp): + if x == 'scadfile': + scadfile = getattr(self, x) + + def rename_scadfile(scadfile): + sf = ''.join(os.path.basename(scadfile).split('.')[:-1]) + scadfile_renamed = sf.lower().strip('_').strip('-') + return(scadfile_renamed) + with open(scadfile) as f: + content = f.readlines() + content = ''.join(content).rstrip('\n') + sc = rename_scadfile(scadfile) + module = 'module {sc}() {{{content};}}\n'.format(**{'content': content, 'sc': sc}) + module = module.replace(';;', ';') + self.modules.append(module) + if fp is not None: + fp.write(module) + content = '{}()'.format(sc) + return(content) + elif x == 'file': + content = getattr(self, x) + if not content.startswith('"'): + content = '"' + content + if not content.endswith('"'): + content = content + '"' + return(content) + else: + return(getattr(self, x)) + args = "" # no-keyword args no_kw_args = list(filter(lambda x: is_no_keyword_args(x), valid_keys)) @@ -113,23 +150,24 @@ def convert_special_args(arg_name): # keyword args kw_args = filter(lambda x: is_keyword_args(x), valid_keys) - args += " ".join(map(lambda x: "{}={},".format(convert_special_args(x), getattr(self, x)), kw_args))[:-1] + args += " ".join(map(lambda x: "{}={},".format(convert_special_args(x), _get_attr(self, x, fp)), kw_args))[:-1] + args = args.replace('scadfile=', '') return args - def _get_children_content(self, indent_level=0): + def _get_children_content(self, indent_level=0, fp=None): _content = "" if len(self.children) > 0: for child in self.children: - _content += child.dumps(indent_level) + _content += child.dumps(indent_level, fp) return _content - def _get_content(self, indent_level=0): + def _get_content(self, indent_level=0, fp=None): if len(self.children) == 0: return "" else: return "{{\n{children}{indent}}}".format( - children=self._get_children_content(indent_level + 1), + children=self._get_children_content(indent_level + 1, fp=fp), indent=INDENT * indent_level ) @@ -151,16 +189,24 @@ def append(self, obj): return self def dump(self, fp): - fp.write(self.dumps()) - - def dumps(self, indent_level=0): - return "{indent}{prefix}{op_name}({params}){content};\n".format( - indent=INDENT * indent_level, - prefix=self.mod.get_prefix(), - op_name=self._name, - params=self._get_params(), - content=self._get_content(indent_level) - ) + dumps = self.dumps(fp=fp) + fp.write(dumps) + + def dumps(self, indent_level=0, fp=None): + if self._name == "scad": + return "{indent}{prefix}{params};\n".format( + indent=INDENT * indent_level, + prefix=self.mod.get_prefix(), + params=self._get_params(fp).replace('True', 'true') + ) + else: + return "{indent}{prefix}{op_name}({params}){content};\n".format( + indent=INDENT * indent_level, + prefix=self.mod.get_prefix(), + op_name=self._name, + params=self._get_params(fp).replace('True', 'true'), + content=self._get_content(indent_level, fp=fp) + ) def write(self, filename, with_print=False): with open(filename, "w") as fp: @@ -248,10 +294,22 @@ def offset(self, *args, **kwargs): from .transformations import Offset return Offset(*args, **kwargs).append(self) + def minkowski(self, *args, **kwargs): + from .transformations import Minkowski + return Minkowski(*args, **kwargs).append(self) + + def hull(self, *args, **kwargs): + from .transformations import Hull + return Hull(*args, **kwargs).append(self) + def linear_extrude(self, *args, **kwargs): from .transformations import Linear_Extrude return Linear_Extrude(*args, **kwargs).append(self) + def rotate_extrude(self, *args, **kwargs): + from .transformations import Rotate_Extrude + return Rotate_Extrude(*args, **kwargs).append(self) + BaseObject = _BaseObject @@ -260,3 +318,11 @@ class _Empty(_BaseObject): pass Empty = _Empty + + +class Scad(_BaseObject): + pass + + +class Import(_BaseObject): + pass diff --git a/openpyscad/custom2dshapes.py b/openpyscad/custom2dshapes.py new file mode 100644 index 0000000..02f3f20 --- /dev/null +++ b/openpyscad/custom2dshapes.py @@ -0,0 +1,27 @@ +from math import cos, sin, pi + +import openpyscad as ops + + +class Custom2dShapes(object): + + @staticmethod + def regular_polygon(num, r): + points = list() + for i in range(num): + a_deg = i * 360 / num + a_rad = a_deg * 2 * pi / 360 + points += [[r * cos(a_rad), r * sin(a_rad)]] + regular_poly = ops.Polygon(points) + return(regular_poly) + + @staticmethod + def star(num, radii): + points = list() + for i in range(num): + a_deg = i * 360 / num + a_rad = a_deg * 2 * pi / 360 + r = radii[i % len(radii)] + points += [[r * cos(a_rad), r * sin(a_rad)]] + star_object = ops.Polygon(points) + return(star_object) diff --git a/openpyscad/custom3dshapes.py b/openpyscad/custom3dshapes.py new file mode 100644 index 0000000..6044f40 --- /dev/null +++ b/openpyscad/custom3dshapes.py @@ -0,0 +1,38 @@ +from math import cos, sin, pi + +import openpyscad as ops + + +class Custom3dShapes(object): + + @staticmethod + def dice(edge=15, fn=32): + """ dice + """ + edge = float(edge) + # dice + c = ops.Cube(edge, center=True) + s = ops.Sphere(edge * 3 / 4, center=True) + dice = c & s + # points + c = ops.Circle(edge / 12, _fn=fn) + h = 0.7 + point = c.linear_extrude(height=h) + point1 = point.translate([0, 0, edge / 2 - h / 2]) + point2_1 = point1.rotate(a=90, v=[1, 0, 0]).translate([edge / 6, 0, edge / 6]) + point2_2 = point2_1.mirror([-edge / 6, 0, -edge / 6]) + point2 = point2_1 + point2_2 + point3 = point2.rotate(a=90, v=[0, 0, 1]) + point1.rotate(a=90, v=[0, 1, 0]) + point4_12 = point2.rotate(a=-90, v=[0, 0, 1]) + point4 = point4_12 + point4_12.mirror([0, 1, 0]) + point5_123 = point3.rotate(a=90, v=[0, 0, 1]) + point5 = point5_123 + point5_123.mirror([1, 0, 0]) + point6_1 = point.translate([0, 0, -(edge / 2 + h / 2)]).translate([0, edge / 6, 0]) + point6_2 = point6_1.translate([edge / 4, 0, 0]) + point6_3 = point6_1.translate([-edge / 4, 0, 0]) + point6_123 = point6_1 + point6_2 + point6_3 + point6_456 = point6_123.mirror([0, 1, 0]) + point6 = point6_123 + point6_456 + dice_with_holes = dice - point1 - point2 - point3 - point4 - point5 - point6 + dice_with_holes = dice_with_holes.mirror([0, 0, 1]) + return(dice_with_holes) diff --git a/openpyscad/shapes_3d.py b/openpyscad/shapes_3d.py index 4a5179e..97ac90b 100644 --- a/openpyscad/shapes_3d.py +++ b/openpyscad/shapes_3d.py @@ -2,7 +2,7 @@ from .base import _BaseObject -__all__ = ["Sphere", "Cube", "Cylinder", "Polyhedron"] +__all__ = ["Sphere", "Cube", "Cylinder", "Polyhedron", "Surface"] # 3D @@ -24,3 +24,7 @@ class Cylinder(_Shape3dObject): class Polyhedron(_Shape3dObject): pass + + +class Surface(_Shape3dObject): + pass diff --git a/openpyscad/transformations.py b/openpyscad/transformations.py index 740b5b3..e0b5d05 100644 --- a/openpyscad/transformations.py +++ b/openpyscad/transformations.py @@ -1,36 +1,41 @@ # -*- coding: utf-8 -*- import openpyscad.base as base +__all__ = ["Translate", "Rotate", "Scale", "Resize", "Mirror", "Color", "Offset", "Hull", "Minkowski", "Linear_Extrude", "Rotate_Extrude"] -__all__ = ["Translate", "Rotate", "Scale", "Resize", "Mirror", "Color", "Offset", "Hull", "Minkowski", "Linear_Extrude"] + +class _Transformation(base.BaseObject): + pass + +Transformation = _Transformation # Transformations -class Translate(base.BaseObject): +class Translate(_Transformation): pass -class Rotate(base.BaseObject): +class Rotate(_Transformation): pass -class Scale(base.BaseObject): +class Scale(_Transformation): pass -class Resize(base.BaseObject): +class Resize(_Transformation): pass -class Mirror(base.BaseObject): +class Mirror(_Transformation): pass -class Color(base.BaseObject): +class Color(_Transformation): pass -class Offset(base.BaseObject): +class Offset(_Transformation): def _validate_append(self, obj): from .shapes_2d import Shape2dObject @@ -38,13 +43,23 @@ def _validate_append(self, obj): raise TypeError("Appended object must be a instance of Shape2dObject.") -class Hull(base.BaseObject): +class Hull(_Transformation): pass -class Minkowski(base.BaseObject): +class Minkowski(_Transformation): pass -class Linear_Extrude(base.BaseObject): - pass +class Linear_Extrude(_Transformation): + def _validate_append(self, obj): + from .shapes_2d import Shape2dObject + if not isinstance(obj, (Shape2dObject, Transformation)): + raise TypeError("Appended object must be a instance of Shape2dObject or Transformation.") + + +class Rotate_Extrude(_Transformation): + def _validate_append(self, obj): + from .shapes_2d import Shape2dObject + if not isinstance(obj, (Shape2dObject, Transformation)): + raise TypeError("Appended object must be a instance of Shape2dObject.") diff --git a/tests/test_base.py b/tests/test_base.py index e46f583..ec006e3 100644 --- a/tests/test_base.py +++ b/tests/test_base.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- import unittest +import os from openpyscad import * @@ -199,9 +200,45 @@ def test_offset(self): with self.assertRaises(TypeError): o.offset([10, 10, 10]) + def test_hull(self): + c = Cube(10) + s = Sphere(3) + s = s.translate([8, 0, 0]) + h = (c + s).hull() + self.assertTrue('hull' in h.dumps()) + + def test_minkowski(self): + c = Cube(10) + s = Sphere(3) + s = s.translate([8, 0, 0]) + h = (c + s).minkowski() + self.assertTrue('minkowski' in h.dumps()) + def test_linear_extrude(self): o = Circle(10) o1 = o.linear_extrude(height=1.6) self.assertTrue(isinstance(o1, Linear_Extrude)) self.assertEqual(o1.children, [o]) - + + def test_rotate_extrude(self): + o = Circle(10) + o1 = o.rotate_extrude() + self.assertTrue(isinstance(o1, Rotate_Extrude)) + self.assertEqual(o1.children, [o]) + + def test_scad_write(self): + sc = Scad(os.path.join(os.path.dirname(os.path.abspath(__file__)),'..','example','example.scad')) + self.assertTrue('example' in sc.dumps()) + sc.write('example_module.scad') + + def test_scad(self): + o = Sphere(3) + sc = Scad(os.path.join(os.path.dirname(os.path.abspath(__file__)),'..','example','example.scad')) + osc = o + sc + self.assertTrue('example' in osc.dumps()) + + def test_import(self): + o = Sphere(3) + sc = Import(os.path.join(os.path.dirname(os.path.abspath(__file__)),'..','example','example.stl')) + osc = o + sc + self.assertTrue('example.stl' in osc.dumps()) diff --git a/tests/test_custom2dshapes.py b/tests/test_custom2dshapes.py new file mode 100644 index 0000000..394798d --- /dev/null +++ b/tests/test_custom2dshapes.py @@ -0,0 +1,14 @@ +import unittest +from openpyscad.custom2dshapes import Custom2dShapes as c2d + + +class TestCustom2dShapes(unittest.TestCase): + + def test_regular_polygon(self): + triangle = c2d.regular_polygon(3, 10) + self.assertTrue(triangle.dumps().startswith("polygon(points=[[10.0, 0.0], [-4.99")) + + def test_star(self): + c = c2d.star(20, [6, 10]) + self.assertTrue(c.dumps().startswith("polygon(points=[[6.0, 0.0], [9.5")) + diff --git a/tests/test_custom3dshapes.py b/tests/test_custom3dshapes.py new file mode 100644 index 0000000..ddd809e --- /dev/null +++ b/tests/test_custom3dshapes.py @@ -0,0 +1,9 @@ +import unittest +from openpyscad.custom3dshapes import Custom3dShapes as c3d + + +class TestCustom3dShapes(unittest.TestCase): + + def test_dice(self): + dice = c3d.dice(15) + self.assertTrue(dice.dumps().startswith("mirror(")) diff --git a/tests/test_transformations.py b/tests/test_transformations.py index cb77da3..5ec223b 100644 --- a/tests/test_transformations.py +++ b/tests/test_transformations.py @@ -13,3 +13,24 @@ def test_validate_append(self): c2 = Cube(10) with self.assertRaises(TypeError): offset.append(c2) + +class TestLinearExtrude(unittest.TestCase): + + def test_validate_append_linear_extrude(self): + c1 = Circle(10) + c2 = c1.linear_extrude(height=1.4) + + c3 = Cube(10) + with self.assertRaises(TypeError): + c3.linear_extrude(height=1.2) + +class TestRotateExtrude(unittest.TestCase): + + def test_validate_append_rotate_extrude(self): + c1 = Circle(10) + c2 = c1.rotate_extrude(angle=90) + + c3 = Cube(10) + with self.assertRaises(TypeError): + c3.rotate_extrude(angle=90) +