diff --git a/README.md b/README.md index 4b1b546..d39f16a 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,10 @@ It also contains convenience functions to define a wider range of primitives, as ## Example ``` -Cube([1, 1, 2]).move([0, 0, 1]) +Cube([1, 1, 2]).move([0, 0, 1]).render() ``` -becomes +returns ``` @@ -25,11 +25,29 @@ translate(v=[0, 0, 1]) { cube(size=[1, 1, 2], center=false); } ## Notable convenience functions -- Usual computational geometry functions on the `Point` class that work in an arbitrary number of dimensions. Overloads for algebraic operators +Usual computational geometry functions on the `Point` class that work in an arbitrary number of dimensions. Overloads for algebraic operators. -- `Cylinder.from_ends` constructs a cylinder between two given points in space +``` +distance = (Point((0, 0, 1)) - Point((1, 0, 1))).length() +angle_between = Point((0, 0, 1) * 2).angle(Point((1, 0, 1))) +``` -- `Polyhedron.tube` creates a tube-like or toroid polyhedron from a 2D array of points +`Cylinder.from_ends()` constructs a cylinder between two given points in space -- `PathTube` creates a tube-like or toroid polyhedron from an arbitrary path +``` +openscad_code = Cylinder.from_ends(radius=2, p1=(0, 0, 1), p2=(1, 0, 2)).render() +``` +`Polyhedron.tube()` creates a tube-like or toroid polyhedron from a 2D array of points + +`PathTube` creates a tube-like or toroid polyhedron from an arbitrary path + +``` +PathTube( + points=[(0,0,0), (0,0,1), (1,0,2), (1,1,0), (0,.5,0)], + radius=.2, + fn=4 +) +``` + +![PathTube example](https://raw.github.com/csirmaz/openscad-py/master/images/pathtube.png) diff --git a/images/pathtube.png b/images/pathtube.png new file mode 100644 index 0000000..f1995bf Binary files /dev/null and b/images/pathtube.png differ diff --git a/openscad_py.py b/openscad_py.py index 64c3f86..1a320d4 100644 --- a/openscad_py.py +++ b/openscad_py.py @@ -9,14 +9,14 @@ NP_TYPE = np.float_ class Point: - """Represents a point of vector in arbitrary dimensions""" + """Represents a point or vector in arbitrary dimensions""" def __init__(self, coords): self.c = np.array(coords, dtype=NP_TYPE) @classmethod def c(cls, coords: TUnion[list, 'Point']) -> 'Point': - """Ensure coords is an instance of Point""" + """Ensure coords is an instance of Point (idempotent)""" if isinstance(coords, Point): return coords return Point(coords) @@ -177,10 +177,12 @@ class Object: return Difference(subject=self, tool=tool) def union(self, objects: TUnion[list, 'Object']) -> 'Object': + """Form the union of self and an object or list of objects""" return Union(child=Collection.c(objects)._add(self)) class Header: + """Render a header (setting global values) of an OpensCAD file""" def __init__(self, quality: str = 'draft'): self.quality = quality @@ -451,13 +453,14 @@ class Polygon(Object): class Collection(Object): + """Represents a collection of objects""" def __init__(self, coll: list): self.collection = coll @classmethod def c(cls, coll: TUnion[list, Object]) -> Object: - """Cast lists to collections""" + """Ensure the list of objects is a Collection (idempotent)""" if isinstance(coll, Object): return coll return cls(coll) @@ -494,8 +497,8 @@ class Rotate(Object): class Scale(Object): - def __init__(self, v: TUnion[list, Point, float], child: Object): - if isinstance(v, float): + def __init__(self, v: TUnion[list, Point, float, int], child: Object): + if isinstance(v, float) or isinstance(v, int): v = [v, v, v] self.v = Point.c(v) self.child = child