### Install PyQt5 from Linux repositories Source: https://pymadcad.readthedocs.io/en/latest/installation Install PyQt5 and its OpenGL bindings from Linux repositories. This is an alternative to installing PyQt5 via pip. ```bash sudo apt install python3-pyqt5 python3-pyqt5.qtopengl ``` -------------------------------- ### Install PyQt5 from PyPI Source: https://pymadcad.readthedocs.io/en/latest/installation Install the PyQt5 library from PyPI. This is one of the options for satisfying the PyQt5 dependency when building from source. ```bash pip install PyQt5 ``` -------------------------------- ### Install pymadcad from PyPI Source: https://pymadcad.readthedocs.io/en/latest/installation Install the base pymadcad package using pip. Ensure you have Python 3.8 or newer. ```bash pip install pymadcad ``` -------------------------------- ### Install pymadcad with optional dependencies Source: https://pymadcad.readthedocs.io/en/latest/installation Install pymadcad along with optional dependencies for STL, PLY, and OBJ file support. This command installs the base package and the specified extras. ```bash pip install pymadcad[stl,ply,obj] ``` -------------------------------- ### Install Debian build dependencies Source: https://pymadcad.readthedocs.io/en/latest/installation Install essential build tools for Debian-based systems. These are required when compiling pymadcad from source. ```bash apt install gcc binutils python3-dev ``` -------------------------------- ### Repeat - Rotation Example Source: https://pymadcad.readthedocs.io/en/latest/guide/generation Generates a complex profile by repeatedly rotating a set of primitives around an axis. This example creates a spiral-like structure. Use `rotatearound` for rotation around a specific axis. ```python from madcad import * # Parameters angle = pi / 13 R = 20 # Points A = vec3(0.95 * R, 0, 0) B = vec3(R * cos(0.05 * angle), R * sin(0.05 * angle), 0) C = vec3(R * cos(0.95 * angle), R * sin(0.95 * angle), 0) D = vec3(0.95 * R * cos(angle), 0.95 * R * sin(angle), 0) # Primitives + web primitives = [Segment(A, B), ArcCentered((O, Z), B, C), Segment(C, D)] # Apply the function repeat with # the transformation `rotatearound(angle, (O, -Z))` web_repeat = repeat(web(primitives), 26, rotatearound(angle, (O, -Z))) web_repeat.mergeclose() m = extrusion(5 * Z, fill(web_repeat.flip() + web(Circle((O, Z), 15)))) show([m]) ``` -------------------------------- ### Extrusion Example Source: https://pymadcad.readthedocs.io/en/latest/guide/generation Generates a mesh by extruding a profile along a specified direction. Includes creating top and bottom surfaces for a closed volume. Use `.flip()` to create holes or reverse surface orientation. ```python from madcad import * ext_circle = Circle((O, Z), 10) int_circle = Circle((O, Z), 5) # Create outline for extrusion to get the lateral surface profile = web(ext_circle) + web(int_circle).flip() # .flip() to make a hole # Create top and bottom surface head = fill(profile) bottom = head.flip() # .flip() to reverse bright and dark surface head = head.transform(10 * (Z + 0.2 * Y)) # Generate extrusion of `profile` with the direction `10 * (Z + 0.2 * Y)` m = extrusion(10 * (Z + 0.2 * Y), profile) + head + bottom show([m]) ``` -------------------------------- ### Install module dependencies for pymadcad Source: https://pymadcad.readthedocs.io/en/latest/installation Install core Python module dependencies required by pymadcad. These are necessary when building from source. ```bash pip install moderngl pyglm pillow numpy scipy pyyaml arrex ``` -------------------------------- ### Place Solid with Specific Joint Type Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly This example demonstrates using `place` with a specific joint type, `Revolute`, to define the relationship between two parts based on an axis and a placement surface. ```python >>> screw.place( ... (Revolute, screw['axis'], other['screw_place']), ... ) ``` -------------------------------- ### get(space) Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Retrieves objects that potentially intersect with the given primitive. Refer to `keysfor` for a description of allowed primitives. ```APIDOC ## get(space) ### Description Gets the objects potentially intersecting the given primitive. Check `keysfor` for a description of allowed primitives. ### Parameters - **space** (primitive) - The primitive to check for intersections. ### Yields - **object** - Objects that potentially intersect with the given primitive. ``` -------------------------------- ### Revolution Example Source: https://pymadcad.readthedocs.io/en/latest/guide/generation Creates a surface of revolution by rotating a 2D section around an axis. Ensure the section is a `Wire` and use `.flip()` if necessary. For closed sections, use `.closed()` on the `Wire`. ```python from madcad import * # Create a section points = [O, X, X + Z, 2 * X + Z, 2 * (X + Z), X + 2 * Z, X + 5 * Z, 5 * Z] section = Wire(points).segmented().flip() # Create a revolution of `section` with the angle `2 * pi` # around the axis `(O, Z)` rev = revolution(2 * pi, (O, Z), section) rev.mergeclose() show([rev]) ``` -------------------------------- ### Repeat - Translation Example Source: https://pymadcad.readthedocs.io/en/latest/guide/generation Applies a translation transformation multiple times to a wire. Use `segmented()` for wires composed of multiple segments and `mergeclose()` to ensure continuity. ```python from madcad import * w = Wire([Y, X + Y, X + 2 * Y, 2 * (X + Y), 2 * X + Y]).segmented() # Apply repeat function with the transformation `translate(2 * X)` web_repeat = repeat(w, 3, translate(2 * X)) web_repeat.mergeclose() show([web_repeat]) ``` -------------------------------- ### Read and Write STL Files Source: https://pymadcad.readthedocs.io/en/latest/guide/io Requires installation of specific dependencies for STL, PLY, and OBJ file support. This snippet shows how to write a generated solid to an STL file and then read it back. ```python from madcad import * s = screw(10, 20) # s is a `Solid` # Write io.write(s["part"], "screw.stl") # Read read_mesh = io.read("screw.stl") read_mesh.mergeclose() show([read_mesh]) ``` -------------------------------- ### Create an Icosphere Mesh Source: https://pymadcad.readthedocs.io/en/latest/reference/generation Generates an icosphere with adjustable resolution. It starts with an icosahedron, subdivides it, and then reprojects the points onto a sphere of the desired radius. ```python def icosphere(center:vec3, radius:float, resolution=None) -> 'Mesh': ''' A simple icosphere with an arbitrary resolution (see https://en.wikipedia.org/wiki/Geodesic_polyhedron). ![icosphere result](../screenshots/generation-icosphere.png) Points are obtained from a subdivided icosahedron and reprojected on the desired radius. ''' div = settings.curve_resolution(2/6*pi*radius, 2/6*pi, resolution) ico = icosahedron(center, radius).subdivide(div-1) for i,p in enumerate(ico.points): ico.points[i] = center + radius * normalize(p-center) return ico ``` -------------------------------- ### Calculate Placement Transformation Matrix Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly Use `placement` to get the transformation matrix for assembling parts based on surface pairs. This is useful when precise manual pose estimation is difficult. The function solves for the pose of the first solid relative to the second, satisfying defined constraints. ```python >>> # get the transformation for the pose >>> pose = placement( ... (screw['part'].group(0), other['part'].group(44)), # two cylinder surfaces: Cylindrical joint ... (screw['part'].group(4), other['part'].group(25)), # two planar surfaces: Planar joint ... ) # solve everything to get solid's pose >>> # apply the transformation to the solid >>> screw.pose = pose ``` -------------------------------- ### Solid.__init__ implementation Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly Initialize a Solid with optional arguments and keyword arguments, setting up the pose matrix as an identity matrix if not provided. ```python def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.__dict__ = self if 'pose' not in self: self.pose = mat4() ``` -------------------------------- ### Create a Solid with objects Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly Initialize a Solid with arbitrary content as keyword arguments. The Solid acts as a dictionary with an automatic pose matrix. ```python >>> mypart = icosphere(vec3(0), 1) >>> s = Solid(part=mypart, anything=vec3(0)) # create a solid with whatever inside ``` -------------------------------- ### Solid.place method Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly Apply a placement transformation to the solid, equivalent to transform(placement(...)). ```python def place(self, *args, **kwargs) -> 'Solid': ''' Strictly equivalent to `.transform(placement(...))`, see `placement` for parameters specifications. ''' return self.transform(placement(*args, **kwargs)) ``` -------------------------------- ### Boolean Operation Between Meshes Source: https://pymadcad.readthedocs.io/en/latest/reference/boolean Example demonstrating the `boolean` operation between two `Mesh` objects. This example uses `sides=(False, False)` to retain the exterior portions of the meshes. ```python w, h = 3, 2 rect = flatsurface( wire([vec3(-w, -h, 0), vec3(w, -h, 0), vec3(w, h, 0), vec3(-w, h, 0)]) ) a = rect.transform(Z) + rect.transform(-Z).flip() b = extrusion(flatsurface(Circle((O, Z), 1.5)).flip(), 4 * Z, alignment=0.5) result = boolean(a, b, (False, False)) ``` -------------------------------- ### Apply Placement Transformation Directly Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly The `place` method offers a convenient way to apply the calculated placement transformation directly to a solid. It accepts the same surface pair definitions as the `placement` function. ```python >>> # or >>> screw.place( ... (screw['part'].group(0), other['part'].group(44)), ... (screw['part'].group(4), other['part'].group(25)), ... ) ``` -------------------------------- ### Solid.display method Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly Create a SolidDisplay object for rendering the Solid in a scene. ```python def display(self, scene): from .displays import SolidDisplay return SolidDisplay(scene, self) ``` -------------------------------- ### Arrange face indices with a specific starting point Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Rotates face indices so that a given point `p` is the first index. Useful for consistent face processing when the starting vertex is important. ```python def arrangeface(f, p): """ Return the face indices rotated the way `p` is the first index, if `p` is in the face """ if p == f[1]: return f[1],f[2],f[0] elif p == f[2]: return f[2],f[0],f[1] else: return f ``` -------------------------------- ### Boolean Operation Between Webs Source: https://pymadcad.readthedocs.io/en/latest/reference/boolean Example demonstrating the `boolean` operation between two `Web` objects. This specific example uses `sides=(False, False)` which typically results in keeping the exterior parts of both webs. ```python w, h = 2, 1 a = web( wire([vec3(-w, -h, 0), vec3(w, -h, 0), vec3(w, h, 0), vec3(-w, h, 0)]) .close() .segmented() ) b = web(Circle((O, Z), 1.5)) result = boolean(a, b, (False, False)) ``` -------------------------------- ### evaluate(x) Source: https://pymadcad.readthedocs.io/en/latest/reference/constraints Places the given values into the system and then fits all constraints. ```APIDOC ## evaluate(x) ### Description First, this method updates the system's state using the provided values in `x` by calling `self.place(x)`. Then, it calculates and returns the residuals of all constraints by calling `self.fit()`. ### Method Signature def evaluate(self, x): ### Parameters - **x** (np.ndarray): An array of values to set in the constraint system. ### Returns - **residuals** (typedlist[float]): A list containing the residual values after applying `x` and fitting the constraints. ``` -------------------------------- ### Get Constraint Points (slvvars) Source: https://pymadcad.readthedocs.io/en/latest/reference/constraints Returns the points associated with the constraint. Use this to access the geometric data of the constraint. ```python def slvvars(self): return self.pts ``` -------------------------------- ### Get Item from PointSet Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Returns the index of the point at the given location in the set. Raises an IndexError if the position does not exist. ```python def __getitem__(self, pt) -> int: ''' return the index of the point at given location in the set ''' for key in self.keysfor(pt): if key in self.dict: return self.dict[key] raise IndexError("position doesn't exist in set") ``` -------------------------------- ### Initialize Problem with constraints and fixed variables Source: https://pymadcad.readthedocs.io/en/latest/reference/constraints The `Problem` class holds data for solving. It registers constraints and variables, determining the problem's dimension. ```python def __init__(self, constraints, fixed=()): self.constraints = set() self.slvvars = {} self.dim = 0 for cst in constraints: # cst can contains objects that are not constraints if hasattr(cst, 'fit'): self.register(cst) for prim in fixed: self.unregister(prim) for v in self.slvvars.values(): if isinstance(v, tuple): self.dim += 1 else: self.dim += len(v) ``` -------------------------------- ### `brick(*args, **kwargs)` Source: https://pymadcad.readthedocs.io/en/latest/reference/generation Constructs a simple brick with rectangular axis-aligned sides. It can be initialized using a `Box` object, or by providing minimum and maximum coordinates, or by specifying the center, size, and alignment. ```APIDOC ## `brick(*args, **kwargs)` ### Description A simple brick with rectangular axis-aligned sides. It can be constructed in the following ways: * `brick(Box)` * `brick(min, max)` * `brick(center=vec3(0), size=vec3(-inf), alignment=0.5)` ### Parameters - `min` (type: unspecified) - Required - the corner with minimal coordinates - `max` (type: unspecified) - Required - the corner with maximal coordinates - `center` (type: unspecified) - Required - the center of the box - `size` (type: unspecified) - Required - the all positive diagonal of the box - `alignment` (type: unspecified) - Required - where the center is inside the box ### Source Code ```python def brick(*args, **kwargs) -> 'Mesh': ''' A simple brick with rectangular axis-aligned sides ![brick result](../screenshots/generation-brick.png) It can be constructed in the following ways: - `brick(Box)` - `brick(min, max)` - `brick(center=vec3(0), size=vec3(-inf), alignment=0.5)` Parameters: min: the corner with minimal coordinates max: the corner with maximal coordinates center: the center of the box size: the all positive diagonal of the box alignment: where the center is inside the box ''' if len(args) == 1 and not kwargs and isinstance(args[0], Box): box = args[0] else: box = Box(*args, **kwargs) mesh = Mesh( [ vec3(1, 0, 0), vec3(1, 0, 1), vec3(0, 0, 1), vec3(0, 0, 0), vec3(1, 1, 0), vec3(1, 1, 1), vec3(0, 1, 1), vec3(0, 1, 0)], [ uvec3(0, 1, 2), uvec3(0, 2, 3), uvec3(4, 7, 6), uvec3(4, 6, 5), uvec3(0, 4, 5), uvec3(0, 5, 1), uvec3(1, 5, 6), uvec3(1, 6, 2), uvec3(2, 6, 7), uvec3(2, 7, 3), uvec3(4, 0, 3), uvec3(4, 3, 7)], [ 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5 ], [None] * 6, ) for i in range(len(mesh.points)): mesh.points[i] = mesh.points[i]*box.size + box.min return mesh ``` ``` -------------------------------- ### Assemble a Custom Gear from Components Source: https://pymadcad.readthedocs.io/en/latest/reference/gear Assembles a gear by combining its exterior, structure, and a custom hub. Requires defining each part separately. ```python >>> # this assemble a gear specifying each independant sub-parts >>> ext_radius = (3 * 12) / (2 * pi) - 3 >>> int_radius = 4 >>> geather( ... gearexterior(repeataround(gearprofile(3, 30), 30), depth=4), ... gearstructure("rounded", ext_radius, int_radius, 2, patterns=6), ... my_hub_mesh, ... ) ``` -------------------------------- ### Create a basic revolution of a section Source: https://pymadcad.readthedocs.io/en/latest/guide/goodpractices Defines points for a section and creates a revolution. Use this as a starting point for revolved shapes. ```python from madcad import * points = [O, X, X + Z, 2 * X + Z, 2 * (X + Z), X + 2 * Z, X + 5 * Z, 5 * Z] section = Wire(points) rev = revolution(section) show([section, rev.transform(translate(6 * X))]) ``` -------------------------------- ### Get iterator of values Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Returns an iterator over the values stored in the hash table. This method directly returns the values from the internal table. ```python def values(self): ''' iterator of the values ''' return self._table.values() ``` -------------------------------- ### display Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly Renders the solid within a given scene. ```APIDOC ## display(scene) ### Description Displays the solid in the provided scene. ### Parameters - `scene`: The scene object to render the solid in. ### Returns - An object representing the solid's display in the scene. ``` -------------------------------- ### place Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly Strictly equivalent to `.transform(placement(...))`, used for positioning the solid. ```APIDOC ## place(*args, **kwargs) ### Description Strictly equivalent to `.transform(placement(...))`, see `placement` for parameters specifications. ### Parameters - `*args`: Positional arguments for `placement`. - `**kwargs`: Keyword arguments for `placement`. ### Returns - A new `Solid` instance positioned according to the `placement` parameters. ``` -------------------------------- ### Get objects intersecting a primitive Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Retrieves objects that potentially intersect with a given primitive. Consult `keysfor` for allowed primitive types. ```python def get(self, space): ''' get the objects potentially intersecting the given primitive check `keysfor` for a description of allowed primitives ''' for k in self.keysfor(space): if k in self.dict: yield from self.dict[k] ``` -------------------------------- ### Get the current state of constraint variables Source: https://pymadcad.readthedocs.io/en/latest/reference/constraints Retrieves the current values of all variables managed by the constraint system into a NumPy array. Useful for optimization routines. ```python def state(self): x = np.empty(self.dim, dtype='f8') i = 0 for v in self.slvvars.values(): l = len(v) x[i:i+l] = v i += l return x ``` -------------------------------- ### Compile pymadcad module from source Source: https://pymadcad.readthedocs.io/en/latest/installation Build the C++ extensions for pymadcad in-place after extracting the source archive. Navigate to the extracted source directory before running this command. ```bash python setup.py build_ext --inplace ``` -------------------------------- ### join Source: https://pymadcad.readthedocs.io/en/latest/reference/blending Creates a simple straight surface from matching couples of line1 and line2 using mesh indices for lines. ```APIDOC ## join(mesh, line1, line2) ### Description Simple straight surface created from matching couples of line1 and line2 using mesh indices for lines. ### Parameters - **mesh**: The mesh object to add the surface to. - **line1**: The first line object. - **line2**: The second line object. ### Returns None. Modifies the mesh object in place. ``` -------------------------------- ### Get Values for Key in Asso Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Returns an iterable of all values associated with the given key. It handles multiple values stored under the same key by using an internal counter. ```python def __getitem__(self, key): ''' return an iterable of the objects associated to the given key ''' i = 0 while True: k = (i,key) if k not in self._table: break yield self._table[k] i += 1 ``` -------------------------------- ### Check for object intersection with a primitive Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Determines if any stored object intersects with the given primitive. This method leverages the `get` method to check for the existence of intersecting objects. ```python def __contains__(self, space): ''' check if any stored object is potentially intersecting the given primitive ''' return next(self.get(space), None) is not None ``` -------------------------------- ### `placement(*pairs, precision=0.001)` Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly Calculates a transformation matrix to solve placement constraints between surfaces. It takes a list of surface pairs or joint definitions and returns the pose of the first part relative to the second, satisfying the constraints. ```APIDOC ## `placement(*pairs, precision=0.001)` ### Description Return a transformation matrix that solved the placement constraints given by the surface pairs. ### Parameters #### Path Parameters - **pairs** (list) - Required - A list of pairs to convert to kinematic joints. Each item can be a couple of surfaces to convert to joints using `guessjoint`, or a tuple `(joint_type, a, b)` to build joints `joint_type(solida, solidb, a, b)`. - **precision** (float) - Optional - Surface guessing and kinematic solving precision (distance). Defaults to `0.001`. ### Details Each pair defines a joint between two assumed solids. Placement returns the pose of the first relatively to the second, satisfying the constraints. ### Request Example ```python # get the transformation for the pose pose = placement( (screw['part'].group(0), other['part'].group(44)), # two cylinder surfaces: Cylindrical joint (screw['part'].group(4), other['part'].group(25)), # two planar surfaces: Planar joint ) # apply the transformation to the solid screw.pose = pose ``` ### Alternative Usage Examples ```python # or screw.place( (screw['part'].group(0), other['part'].group(44)), (screw['part'].group(4), other['part'].group(25)), ) ``` ```python screw.place( (Revolute, screw['axis'], other['screw_place']), ) ``` ``` -------------------------------- ### Create a key for an oriented face Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Generates a canonical key for an oriented face by ordering its vertices. This function handles different starting vertices to ensure a consistent representation. ```python def facekeyo(a,b,c): """ Return a key for an oriented face """ if a < b and b < c: return (a,b,c) elif a < b: return (c,a,b) else: return (b,c,a) ``` -------------------------------- ### place(x) Source: https://pymadcad.readthedocs.io/en/latest/reference/constraints Updates the state of the constraint system with new values from a given array. ```APIDOC ## place(x) ### Description Updates the internal state of the constraint system with the values provided in the input array `x`. This method distributes the values from `x` to the respective variables managed by the system. ### Method Signature def place(self, x): ### Parameters - **x** (np.ndarray): An array containing the new values to set for the variables. ``` -------------------------------- ### Arrange edge indices with a specific starting point Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Rotates edge indices so that a given point `p` is the first index. This simplifies edge processing when the orientation relative to a specific point is needed. ```python def arrangeedge(e, p): """ Return the edge indices rotated the way `p` is the first index, if `p` is in the edge """ if p == e[1]: return e[1], e[0] else: return e ``` -------------------------------- ### Display Mesh Without Options Source: https://pymadcad.readthedocs.io/en/latest/guide/display Use the `show` function with a list containing the Mesh object to display it with default settings. ```python from madcad import * m = screw(10, 20) show([m]) ``` -------------------------------- ### Asso(iter=None) Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Initializes an Asso container, which is an associative container storing multiple values for each key. ```APIDOC ## Asso(iter=None) ### Description Initializes an Asso container. It can be initialized with an existing Asso object or an iterable of (key, value) pairs. ### Parameters * **iter**: An optional iterable of (key, value) pairs or an existing Asso object to initialize from. ``` -------------------------------- ### Extract Convex Outline from Source Source: https://pymadcad.readthedocs.io/en/latest/reference/hull Extracts the loop formed by edges in the biggest planar projection of the convex hull. It can optionally flatten the outline points to their mean plane. Use this to get the boundary of a projected shape. ```python def convexoutline(source: '[vec3]', normal: vec3=None, flatten: bool=False) -> Web: """ based on `convexhull()` but will extract the loop formed by the edges in the biggest planar projection of the convex hull ![convexoutline result](../screenshots/hull-convexoutline.png) Parameters: source (typedlist/Web/Mesh): the input container, if it is a Web or Mesh, their groups are kept in the output data normal: the projection normal to retreive the outline using `horizon()`, if None is given it will default to the direction in which the outlien surface is the biggest flatten: whether to project the outline points in its mean plane Examples: >>> convexoutline(web([ ... Circle(Axis(O,Z), 1), ... Circle(Axis(4*X,Z), 2), ... ])) """ if isinstance(source, (Mesh,Web,Wire)): source = copy(source) source.strippoints() points = source.points else: points = typedlist(source, dtype=vec3) source = None direction = normal or widest_surface_direction(Mesh(source.points, simple_convexhull(points))) x, y, z = dirbase(direction) proj = transpose(dmat2x3(x, y)) outline = restore_groups(source, simple_convexoutline(typedlist(proj * p for p in points))) .orient(direction) if flatten: outline.strippoints() center = outline.barycenter() outline.points = typedlist(center + noproject(p-center, direction) for p in outline.points) return outline ``` -------------------------------- ### Solid.append method Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly Add an item to the Solid with an automatically generated key and return the key. ```python def append(self, value) -> int: ''' Add an item in self.content, a key is automatically created for it and is returned ''' key = next(i for i in range(len(self.content)+1) if i not in self.content ) self[key] = value return key ``` -------------------------------- ### Get Position Keys for Primitive Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Calculates the spatial hash keys for a given primitive (point, segment, or triangle) based on the PositionMap's cell size. Use this to determine which grid cells a primitive occupies. ```python def keysfor(self, space): """ Rasterize the primitive, yielding the successive position keys currently allowed primitives are :points: vec3 :segments: (vec3,vec3) :triangles: (vec3,vec3,vec3) """ # point if isinstance(space, vec3): return tuple(i64vec3(glm.floor(space/self.cellsize))), # segment elif isinstance(space, tuple) and len(space) == 2: return core.rasterize_segment(space, self.cellsize) # triangle elif isinstance(space, tuple) and len(space) == 3: return core.rasterize_triangle(space, self.cellsize) else: raise TypeError("PositionMap only supports keys of type: points, segments, triangles") ``` -------------------------------- ### Solid.loc method Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly Chain transforms along a given key path to retrieve the combined transformation. ```python def loc(self, *args) -> object: ''' chain transforms in the given key path ''' obj, transform = self._unroll(args) return transform ``` -------------------------------- ### regon Source: https://pymadcad.readthedocs.io/en/latest/reference/generation Creates a regular n-gon Wire, similar to how a Circle is created. ```APIDOC ## regon(axis, radius, n, alignment=vec3(1, 0, 0)) ### Description Create a regular n-gon `Wire`, the same way we create a `Circle`. ### Parameters - **axis**: The axis of the n-gon. - **radius**: The radius of the n-gon. - **n**: The number of sides of the n-gon. - **alignment**: The alignment vector for the n-gon. ### Return A `Wire` object representing the regular n-gon. ``` -------------------------------- ### Create a Saddle Surface Source: https://pymadcad.readthedocs.io/en/latest/reference/generation Use `saddle` to create a surface by extruding one outline and translating it along the points of another outline. Ensure both inputs are valid Web objects. ```python def saddle(a, b:Web) -> Mesh: """ Create a surface by extruding outine1 translating each instance to the next point of outline2 ![saddle result](../screenshots/generation-saddle.png) Examples: >>> saddle( ... ArcThrough(+Y,X,-Y), ... Softened([0*X, 0*X-2*Z, 4*X-2*Z, 4*X]), ... ) """ if not isinstance(a, (Mesh,Web,Wire)): a = web(a) b = web(b) def trans(): s = b.points[0] for p in b.points: yield translate(mat4(1), p-s) return extrans(a, trans(), ((*e,t) for e,t in zip(b.edges, b.tracks))) ``` -------------------------------- ### Evaluate constraints after placing values Source: https://pymadcad.readthedocs.io/en/latest/reference/constraints First places the given values into the constraint variables, then evaluates all constraints and returns their residuals. ```python def evaluate(self, x): self.place(x) return self.fit() ``` -------------------------------- ### display(scene) Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Renders the stored objects within a given scene. ```APIDOC ## display(scene) ### Description Displays the stored objects within a given scene. ### Parameters - **scene** (Scene) - The scene to display the objects in. ### Returns - **mesh.Web** - The rendered web object. ``` -------------------------------- ### PyMadcad Placement Function Implementation Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly The source code for the `placement` function, which processes pairs of surfaces to create kinematic joints and calculates the resulting transformation matrix. It handles different pair definitions and uses `guessjoint` for surface-to-joint conversion. ```python def placement(*pairs, precision=1e-3): ''' Return a transformation matrix that solved the placement constraints given by the surface pairs Parameters: pairs: a list of pairs to convert to kinematic joints - items can be couples of surfaces to convert to joints using `guessjoint` - tuples (joint_type, a, b) to build joints `joint_type(solida, solidb, a, b)` precision: surface guessing and kinematic solving precision (distance) Each pair define a joint between the two assumed solids (a solid for the left members of the pairs, and a solid for the right members of the pairs). Placement will return the pose of the first relatively to the second, satisfying the constraints. suppose we have those parts to assemble and it's hard to guess the precise pose transform between them ![before placement](../screenshots/placement-before.png) placement gives the pose for the screw to make the selected surfaces coincide ![after placement](../screenshots/placement-after.png) Examples: >>> # get the transformation for the pose >>> pose = placement( ... (screw['part'].group(0), other['part'].group(44)), # two cylinder surfaces: Cylindrical joint ... (screw['part'].group(4), other['part'].group(25)), # two planar surfaces: Planar joint ... ) # solve everything to get solid's pose >>> # apply the transformation to the solid >>> screw.pose = pose >>> # or >>> screw.place( ... (screw['part'].group(0), other['part'].group(44)), ... (screw['part'].group(4), other['part'].group(25)), ... ) >>> screw.place( ... (Revolute, screw['axis'], other['screw_place']), ... ) '' from ..reverse import guessjoint from ..kinematic import Kinematic # circular import joints = [] for pair in pairs: if len(pair) == 2: joints.append(guessjoint((0, 1), *pair, precision*0.25)) elif len(pair) == 3: joints.append(pair[0]((0, 1), *pair[1:])) else: raise TypeError('incorrect pair definition', pair) if len(joints) > 1: kin = Kinematic(joints) parts = kin.parts(kin.solve()) return affineInverse(parts[1]) * parts[0] else: return affineInverse(joints[0].direct(joints[0].default)) ``` -------------------------------- ### Initialize Asso Container Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Initializes an Asso container, which acts as a dictionary storing multiple values per key. It can be initialized from another Asso instance or an iterable of (key, value) pairs. ```python def __init__(self, iter=None): if isinstance(iter, Asso): self._table = dict(iter.table) else: self._table = {} if iter: self.update(iter) ``` -------------------------------- ### append Source: https://pymadcad.readthedocs.io/en/latest/reference/assembly Adds an item to the solid's content, automatically creating a key for it. ```APIDOC ## append(value) ### Description Add an item in `self.content`, a key is automatically created for it and is returned. ### Parameters - `value`: The item to add to the solid's content. ### Returns - The automatically generated key for the appended item. ``` -------------------------------- ### facekeyo(a, b, c) Source: https://pymadcad.readthedocs.io/en/latest/reference/hashing Returns a key for an oriented face. ```APIDOC ## facekeyo(a, b, c) ### Description Return a key for an oriented face. ### Parameters - **a** (any) - Description of the first point. - **b** (any) - Description of the second point. - **c** (any) - Description of the third point. ### Returns - (tuple) - A tuple representing the oriented face key. ### Example ```python facekeyo(1, 2, 3) # Returns (1, 2, 3) facekeyo(3, 1, 2) # Returns (1, 2, 3) facekeyo(2, 3, 1) # Returns (1, 2, 3) ``` ``` -------------------------------- ### state() Source: https://pymadcad.readthedocs.io/en/latest/reference/constraints Retrieves the current state of all variables managed by the constraint system. ```APIDOC ## state() ### Description Returns the current state of all variables managed by the constraint system as a NumPy array. ### Method Signature def state(self): ### Returns - **x** (np.ndarray): A NumPy array containing the current values of all variables. ``` -------------------------------- ### Generate Rack Tooth Profile Source: https://pymadcad.readthedocs.io/en/latest/reference/gear Generates a 1-period tooth profile for a rack. Allows customization of height, offset, and asymmetry. ```python def rackprofile(step, height=None, offset=0, asymetry=None, pressure_angle=radians(20), resolution=None) -> Wire: ''' Generate a 1-period tooth profile for a rack ![rackprofile](../screenshots/rackprofile.png) Parameters: step: period length over the primitive line height: tooth half height offset: rack reference line offset with the primitive line (as a distance) - the primitive line is the adherence line with gears - the reference line is the line half the tooth is above and half below pressure_angle: angle of the tooth sides, a.k.a pressure angle of the contact ''' # change name for convenience h = height a = asymetry e = offset if h is None: h = default_height(step, pressure_angle) if a is None: a = -0.1*h ta = tan(pressure_angle) x = 0.5 - 2*e/step*ta # fraction of the tooth above the primitive circle return Wire([ vec3(step*x/2 - ta * ( h-e-a), h-e-a, 0), vec3(step*x/2 - ta * (-h-e-a), -h-e-a, 0), vec3(step*(2-x)/2 + ta * (-h-e-a), -h-e-a, 0), vec3(step*(2-x)/2 + ta * ( h-e-a), h-e-a, 0), vec3(step*(2+x)/2 - ta * ( h-e-a), h-e-a, 0), ], groups=['rack']) ``` -------------------------------- ### Basic Math Operations with madcad Source: https://pymadcad.readthedocs.io/en/latest/guide/overview Demonstrates the usage of basic math types like vec3, X, Y, Z, and operations such as vector addition, scaling, normalization, and rotation. ```python >>> from madcad import * >>> print('\n'.join(map(str, (O, X, Y, Z)))) # already created dvec3( 0, 0, 0 ) dvec3( 1, 0, 0 ) dvec3( 0, 1, 0 ) dvec3( 0, 0, 1 ) >>> A = vec3(3.54, -2.22, 82.17) >>> B = 3.54 * X - 2.22 * Y + 82.17 * Z >>> print(A == B) True >>> normalized_A = normalize(A) >>> print(length(normalized_A)) # also see length2 0.9999999999999999 >>> rot90aroundA = angleAxis(pi / 2, A) >>> print(type(rot90aroundA)) >>> print(type(rotate(pi / 2, A))) >>> print(type(translate(2 * X))) >>> print(rotate(pi / 2, Z) * X) # = Y dvec3( 6.12323e-17, 1, 0 ) >>> print(angleAxis(pi / 2, Z) * X) # = Y dvec3( 2.22045e-16, 1, 0 ) >>> print(translate(Z) * X) # = X + Z dvec3( 1, 0, 1 ) ``` -------------------------------- ### Display Mesh with Points Source: https://pymadcad.readthedocs.io/en/latest/guide/display To display the points of a Mesh, set `display_points` to `True` in the options dictionary. ```python from madcad import * m = screw(10, 20) show([m], options={"display_points":True}) ``` -------------------------------- ### Generate ICO Surface Source: https://pymadcad.readthedocs.io/en/latest/reference/generation Generates an ICO surface by interpolating points using interpol2tri. Use normals for spherical fitting, otherwise provide edge tangents. ```python def icosurface(pts, ptangents, resolution=None) -> 'Mesh': """ Generate a surface ICO (a subdivided triangle) with its points interpolated using interpol2tri. - If normals are given instead of point tangents (for ptangents), the surface will fit a sphere. - Else `ptangents` must be a list of couples (2 edge tangents each point). """ # compute normals to points if isinstance(ptangents[0], tuple): normals = [None]*3 for i in range(3): normals[i] = normalize(cross(ptangents[i][0], ptangents[i][1])) else: # if normals are given instead of tangents, compute tangents to fit a sphere surface normals = ptangents ptangents = [None]*3 for i in range(3): ptangents[i] = ( normalize(noproject(pts[i-2]-pts[i], normals[i])) * arclength(pts[i], pts[i-2], normals[i], normals[i-2]), normalize(noproject(pts[i-1]-pts[i], normals[i])) * arclength(pts[i], pts[i-1], normals[i], normals[i-1]), ) # evaluate resolution (using a bad approximation of the length for now) div = max(( settings.curve_resolution( distance(pts[i-1], pts[i-2]), anglebt(normals[i-1], normals[i-2]), resolution) for i in range(3) )) return dividedtriangle(lambda u,v: intri_sphere(pts, ptangents, u,v), div) ```