yapcad.collision package
Submodules
yapcad.collision.detector module
Main collision detection class with BREP/mesh/AABB methods.
This module defines the CollisionDetector class and GeometryProvider protocol for performing collision detection on assemblies.
Copyright (c) 2026 yapCAD contributors License: MIT
- class yapcad.collision.detector.CollisionDetector(geometry_provider: GeometryProvider, interface_registry: InterfaceRegistry | None = None, verbose: bool = False, min_collision_volume: float = 0.1, mesh_sample_points: int = 1500, penetration_threshold: float = 0.1)[source]
Bases:
objectMain collision detection class with multiple detection methods.
CollisionDetector provides collision detection between assembly parts using the best available method:
BREP detection (if pythonocc available): Uses boolean intersection for exact collision volume
Mesh detection (if trimesh available): Uses point sampling and containment checks
AABB detection (always available): Fast bounding box checks (used as pre-filter)
The detector integrates with InterfaceRegistry to distinguish expected overlaps (gear mesh, threads) from actual collisions.
- geometry_provider
Provider for part geometry
- interface_registry
Registry of allowed overlap interfaces
- verbose
Enable detailed logging
- min_collision_volume
Minimum volume to report (mm^3)
- mesh_sample_points
Number of sample points for mesh detection
- penetration_threshold
Minimum depth to count as collision (mm)
Example
>>> provider = MyGeometryProvider() >>> detector = CollisionDetector(provider) >>> >>> # Optional: register allowed overlaps >>> registry = InterfaceRegistry() >>> registry.register(GearMeshInterface(...)) >>> detector.set_interface_registry(registry) >>> >>> # Check single pair >>> result = detector.check_collision( ... "PART_A", transform_a, ... "PART_B", transform_b ... ) >>> >>> # Check full assembly >>> transforms = {"PART_A": tf_a, "PART_B": tf_b, "PART_C": tf_c} >>> results = detector.check_assembly(transforms) >>> collisions = [r for r in results if r.is_error]
- check_assembly(world_transforms: Dict[str, Any], skip_pairs: List[Tuple[str, str]] | None = None) List[CollisionResult][source]
Check all pairs in an assembly for collisions.
- Parameters:
world_transforms – Dictionary mapping part names to 4x4 transforms
skip_pairs – Optional list of (part_a, part_b) pairs to skip
- Returns:
List of CollisionResult for all pairs checked
- check_collision(part_a: str, transform_a: Any, part_b: str, transform_b: Any, method: CollisionMethod | None = None) CollisionResult[source]
Check for collision between two parts.
- Parameters:
part_a – Name of first part
transform_a – 4x4 transformation matrix for part A
part_b – Name of second part
transform_b – 4x4 transformation matrix for part B
method – Specific detection method (default: best available)
- Returns:
CollisionResult with collision details
- get_collision_summary(results: List[CollisionResult]) Dict[str, Any][source]
Generate summary statistics from collision results.
- Parameters:
results – List of CollisionResult from check_assembly
- Returns:
Dictionary with summary statistics
- property preferred_method: CollisionMethod
Get the preferred detection method based on available libraries.
- set_interface_registry(registry: InterfaceRegistry) None[source]
Set the interface registry for allowed overlaps.
- Parameters:
registry – InterfaceRegistry with interface definitions
- class yapcad.collision.detector.GeometryProvider(*args, **kwargs)[source]
Bases:
ProtocolProtocol for providing geometry data for collision detection.
Implementations must provide a way to retrieve geometry for parts by name. The geometry can be returned as:
Path to STEP file (preferred for BREP detection)
Path to STL file (for mesh detection)
trimesh.Trimesh object (pre-loaded mesh)
TopoDS_Shape object (pre-loaded BREP)
Example
>>> class FileBasedProvider: ... def __init__(self, base_dir: Path): ... self.base_dir = base_dir ... ... def get_geometry(self, part_name: str) -> Optional[str]: ... step_path = self.base_dir / f"{part_name}.step" ... if step_path.exists(): ... return str(step_path) ... stl_path = self.base_dir / f"{part_name}.stl" ... if stl_path.exists(): ... return str(stl_path) ... return None
yapcad.collision.gear_interface module
Gear mesh interface for involute gear teeth overlap.
This module defines the GearMeshInterface class for representing gear teeth meshing regions where controlled overlap is expected.
Copyright (c) 2026 yapCAD contributors License: MIT
- class yapcad.collision.gear_interface.GearMeshInterface(name: str, part_name: str, center: Tuple[float, float, float]=(0.0, 0.0, 0.0), axis: Tuple[float, float, float]=(0.0, 0.0, 1.0), description: str = '', metadata: Dict[str, ~typing.Any]=<factory>, module: float = 1.0, teeth: int = 20, pressure_angle: float = 20.0, face_width: float = 10.0, helix_angle: float = 0.0, backlash: float = 0.0)[source]
Bases:
InterfaceVolumeInterface volume for involute gear teeth meshing.
Defines the region where gear teeth overlap during meshing. Two gears are compatible if they have the same module and pressure angle (standard involute tooth profile).
- Derived Properties:
pitch_diameter: module * teeth addendum: module (tooth height above pitch circle) dedendum: 1.25 * module (tooth depth below pitch circle) outside_diameter: pitch_diameter + 2 * addendum root_diameter: pitch_diameter - 2 * dedendum base_diameter: pitch_diameter * cos(pressure_angle)
Example
>>> sun = GearMeshInterface( ... name="sun_teeth", part_name="SUN_GEAR", ... module=0.75, teeth=18, pressure_angle=20.0, face_width=10.0 ... ) >>> planet = GearMeshInterface( ... name="planet_teeth", part_name="PLANET_GEAR", ... module=0.75, teeth=36, pressure_angle=20.0, face_width=10.0 ... ) >>> result = sun.check_compatibility(planet) >>> print(result) # COMPATIBLE: Gears compatible: m=0.75mm, PA=20.0deg >>> print(f"Center distance: {sun.get_center_distance(planet):.2f}mm")
Notes
Module must match exactly between meshing gears (within 0.1% tolerance)
Pressure angle must match (within 0.5 degree tolerance)
For helical gears, helix angles must be opposite (LH + RH = 0)
Face widths must have sufficient overlap for load transfer
- check_compatibility(other: InterfaceVolume) CompatibilityResult[source]
Check if this gear can mesh with another interface.
- Compatible conditions:
Other must be a GearMeshInterface
Modules must match (within 0.1% tolerance)
Pressure angles must match (within 0.5 degree tolerance)
Helix angles must be compatible (opposite for external mesh)
Face widths must have sufficient overlap
- Parameters:
other – Another interface volume to check against
- Returns:
CompatibilityResult indicating if gears can properly mesh
- get_bounding_cylinder() Tuple[float, float][source]
Get cylindrical bounding volume (radius, height).
- Returns:
Tuple of (radius, height) where radius extends to outside diameter and height is the face width.
- get_center_distance(other: GearMeshInterface) float[source]
Calculate theoretical center distance for meshing with another gear.
- Parameters:
other – Another gear to mesh with
- Returns:
Center-to-center distance for proper meshing in mm
- Raises:
ValueError – If modules don’t match
- get_engagement_depth() float[source]
Face width is the engagement depth for gears.
- Returns:
Face width in mm
- get_expected_overlap_volume(other: GearMeshInterface) float[source]
Calculate expected overlap volume when meshing with another gear.
This provides an estimate of how much volume the gear teeth should overlap when properly meshed, useful for validating collision detection results.
- Parameters:
other – Another gear to mesh with
- Returns:
Estimated overlap volume in mm^3
- get_mesh_overlap_depth() float[source]
Calculate the theoretical tooth mesh overlap depth.
This is the radial depth where teeth from two meshing gears actually overlap, used for collision solver exceptions.
- Returns:
Depth of tooth engagement zone in mm (approximately 2 * module)
- interface_type: InterfaceType = 1
- yapcad.collision.gear_interface.check_gear_mesh_collision(gear_a: GearMeshInterface, gear_b: GearMeshInterface, actual_center_distance: float, tolerance: float = 0.1) CompatibilityResult[source]
Check if two gears are correctly positioned for meshing.
This function verifies both gear compatibility and proper positioning by comparing actual center distance to theoretical.
- Parameters:
gear_a – First gear interface
gear_b – Second gear interface
actual_center_distance – Measured center-to-center distance in mm
tolerance – Allowable deviation from theoretical in mm
- Returns:
CompatibilityResult with mesh status and any warnings
Example
>>> sun = GearMeshInterface(name="sun", part_name="SUN", module=0.75, teeth=18) >>> planet = GearMeshInterface(name="planet", part_name="PLANET", module=0.75, teeth=36) >>> result = check_gear_mesh_collision(sun, planet, actual_center_distance=20.25) >>> if result.is_compatible: ... print("Gears properly meshed")
- yapcad.collision.gear_interface.create_planetary_gearbox_interfaces(gearbox_name: str, module: float, sun_teeth: int, planet_teeth: int, ring_teeth: int, face_width: float, num_planets: int = 3, pressure_angle: float = 20.0, mesh_plane_z: float = 0.0) List[GearMeshInterface][source]
Create interface volumes for a complete planetary gearbox.
This factory function creates GearMeshInterface objects for all gears in a planetary gearbox configuration: one sun, one ring, and multiple planet gears at the correct orbital positions.
- Parameters:
gearbox_name – Base name for the gearbox (e.g., “AXIS1”)
module – Gear module in mm
sun_teeth – Number of teeth on sun gear
planet_teeth – Number of teeth on planet gears
ring_teeth – Number of teeth on ring gear (internal)
face_width – Gear face width in mm
num_planets – Number of planet gears (typically 3)
pressure_angle – Pressure angle in degrees (typically 20.0)
mesh_plane_z – Z coordinate of the gear mesh plane
- Returns:
List of GearMeshInterface objects for all gears
Example
>>> interfaces = create_planetary_gearbox_interfaces( ... gearbox_name="AXIS1", ... module=0.75, ... sun_teeth=18, ... planet_teeth=36, ... ring_teeth=90, ... face_width=10.0, ... num_planets=3 ... ) >>> for iface in interfaces: ... print(f"{iface.name}: {iface.teeth}T at {iface.center}")
Notes
Verifies planetary gear geometry: ring_teeth = sun_teeth + 2 * planet_teeth
Places planets at equal angular intervals
All gears centered at Z = mesh_plane_z
yapcad.collision.interface module
Base interface volume classes for controlled overlap regions.
This module defines the base InterfaceVolume class and InterfaceType enum for describing regions where parts are designed to overlap (gear teeth, threads, press fits, etc.).
Copyright (c) 2026 yapCAD contributors License: MIT
- class yapcad.collision.interface.CompatibilityResult(is_compatible: bool, reason: str, warnings: List[str] = <factory>, overlap_volume: float = 0.0, required_clearance: float = 0.0)[source]
Bases:
objectResult of checking interface compatibility.
When two interface volumes overlap, this result indicates whether they are designed to mate properly (compatible) or represent an unintended collision (incompatible).
Example
>>> result = sun_gear.check_compatibility(planet_gear) >>> if result.is_compatible: ... print(f"Gears can mesh: {result.reason}") ... if result.warnings: ... print(f"Warnings: {result.warnings}") ... else: ... print(f"Incompatible: {result.reason}")
- class yapcad.collision.interface.InterfaceType(*values)[source]
Bases:
EnumTypes of interface volumes for controlled overlap.
Each type represents a specific mechanical interface where geometric overlap is expected and designed.
- GEAR_MESH
Involute gear teeth meshing
- THREAD
Screw thread engagement (bolt/nut, tap/screw)
- PRESS_FIT
Interference fit (shaft/bore)
- BEARING
Bearing race contact regions
- SPLINE
Spline coupling interface
- KEY
Key/keyway interface
- SNAP_FIT
Snap-fit detent mechanism
- CUSTOM
User-defined interface type
- BEARING = 4
- CUSTOM = 8
- GEAR_MESH = 1
- KEY = 6
- PRESS_FIT = 3
- SNAP_FIT = 7
- SPLINE = 5
- THREAD = 2
- class yapcad.collision.interface.InterfaceVolume(name: str, part_name: str, interface_type: InterfaceType, center: Tuple[float, float, float]=(0.0, 0.0, 0.0), axis: Tuple[float, float, float]=(0.0, 0.0, 1.0), description: str = '', metadata: Dict[str, ~typing.Any]=<factory>)[source]
Bases:
ABCBase class for interface volumes that allow controlled overlap.
Interface volumes define regions where parts are DESIGNED to overlap, such as gear teeth meshing, threads engaging, or press fits. The collision detector uses these to distinguish expected overlap from actual collisions.
- Subclasses must implement:
get_bounding_cylinder(): Return (radius, height) of enclosing cylinder
check_compatibility(): Check if another interface can mate properly
get_engagement_depth(): Return the engagement/overlap depth
- interface_type
Type of interface (GEAR_MESH, THREAD, etc.)
- axis
Primary axis direction as (x, y, z) tuple (rotation/engagement axis)
Example
>>> class MyInterface(InterfaceVolume): ... def get_bounding_cylinder(self): ... return (10.0, 5.0) # radius=10mm, height=5mm ... def check_compatibility(self, other): ... if isinstance(other, MyInterface): ... return CompatibilityResult(True, "Compatible") ... return CompatibilityResult(False, "Type mismatch") ... def get_engagement_depth(self): ... return 5.0
- abstractmethod check_compatibility(other: InterfaceVolume) CompatibilityResult[source]
Check if this interface is compatible with another.
Two interfaces are compatible if they are designed to mate properly when overlapping (e.g., matching gear modules, matching thread pitches).
- Parameters:
other – Another interface volume to check against
- Returns:
CompatibilityResult indicating if interfaces can properly mate
- abstractmethod get_bounding_cylinder() Tuple[float, float][source]
Get cylindrical bounding volume for the interface.
- Returns:
Tuple of (radius, height) in mm defining the minimum enclosing cylinder aligned with the interface axis.
- abstractmethod get_engagement_depth() float[source]
Get the depth/length of interface engagement in mm.
- For different interface types:
Gears: face width
Threads: engagement length
Press fits: engagement length
Bearings: bearing width
- Returns:
Engagement depth in mm
- interface_type: InterfaceType
- overlaps_with(other: InterfaceVolume, tolerance: float = 0.1) bool[source]
Check if two interface volumes spatially overlap.
This is a geometric overlap check, not a compatibility check. Two interfaces can overlap geometrically but be incompatible (e.g., mismatched gear modules).
- Parameters:
other – Another interface volume to check
tolerance – Distance tolerance for overlap detection in mm
- Returns:
True if bounding volumes overlap within tolerance
- to_dict() Dict[str, Any][source]
Convert to dictionary for serialization.
- Returns:
Dictionary representation suitable for JSON export
yapcad.collision.registry module
Interface registry for managing allowed overlap regions.
This module defines the InterfaceRegistry class for tracking and querying interface volumes across an assembly.
Copyright (c) 2026 yapCAD contributors License: MIT
- class yapcad.collision.registry.InterfaceRegistry[source]
Bases:
objectRegistry for managing interface volumes in an assembly.
The registry tracks all interface volumes and provides lookup methods for the collision detector to find compatible interfaces when overlap is detected between parts.
- Key Features:
Register/unregister interface volumes by name
Query interfaces by part name or interface type
Check overlap compatibility between parts
Find all compatible interfaces for a given interface
- Usage:
>>> registry = InterfaceRegistry() >>> >>> # Register gear interfaces >>> registry.register(GearMeshInterface( ... name="sun_teeth", part_name="SUN_GEAR", ... module=0.75, teeth=18, pressure_angle=20.0, face_width=10.0 ... )) >>> registry.register(GearMeshInterface( ... name="planet_teeth", part_name="PLANET_GEAR", ... module=0.75, teeth=36, pressure_angle=20.0, face_width=10.0 ... )) >>> >>> # During collision detection >>> is_compatible, results = registry.check_overlap_compatibility( ... "SUN_GEAR", "PLANET_GEAR" ... ) >>> if is_compatible: ... print("Overlap is expected (gear mesh)")
Notes
Interface names must be unique within the registry
Parts can have multiple interfaces (e.g., gear teeth + bearing seat)
The registry does not store geometry, only interface definitions
- check_overlap_compatibility(part_a: str, part_b: str, overlap_region: Tuple[Any, Any] | None = None) Tuple[bool, List[CompatibilityResult]][source]
Check if overlap between two parts is due to compatible interfaces.
This is the main entry point for the collision detector to check whether detected overlap should be allowed (expected interface) or flagged as a collision error.
- Parameters:
part_a – First part name
part_b – Second part name
overlap_region – Optional (center, size) of overlap bounding box for spatial filtering (not yet implemented)
- Returns:
bool: True if ALL overlapping interfaces are compatible
List[CompatibilityResult]: Results for each interface pair checked
- Return type:
Tuple of
Example
>>> is_ok, results = registry.check_overlap_compatibility("SUN", "PLANET") >>> if is_ok: ... print("Expected gear mesh overlap") ... else: ... for r in results: ... if not r.is_compatible: ... print(f"Incompatible: {r.reason}")
- find_compatible_interfaces(interface: InterfaceVolume, candidates: List[InterfaceVolume] = None) List[Tuple[InterfaceVolume, CompatibilityResult]][source]
Find all interfaces compatible with the given interface.
- Parameters:
interface – Interface to find matches for
candidates – List of candidates to check (default: all registered)
- Returns:
List of (interface, compatibility_result) tuples for compatible interfaces
- get(name: str) InterfaceVolume | None[source]
Get interface by name.
- Parameters:
name – Interface name to look up
- Returns:
InterfaceVolume if found, None otherwise
- get_all_interfaces() List[InterfaceVolume][source]
Get all registered interfaces.
- Returns:
List of all InterfaceVolume objects in the registry
- get_all_parts() List[str][source]
Get names of all parts with registered interfaces.
- Returns:
List of part names
- get_compatible_interface_names(part_a: str, part_b: str) List[str][source]
Get names of compatible interfaces between two parts.
Convenience method to get just the interface names for parts that have compatible overlap.
- Parameters:
part_a – First part name
part_b – Second part name
- Returns:
List of compatible interface names (from both parts)
- get_interfaces_by_type(interface_type: InterfaceType) List[InterfaceVolume][source]
Get all interfaces of a specific type.
- Parameters:
interface_type – Type of interface to find
- Returns:
List of matching InterfaceVolume objects (may be empty)
- get_interfaces_for_part(part_name: str) List[InterfaceVolume][source]
Get all interfaces belonging to a part.
- Parameters:
part_name – Name of the part
- Returns:
List of InterfaceVolume objects for the part (may be empty)
- has_interfaces(part_name: str) bool[source]
Check if a part has any registered interfaces.
- Parameters:
part_name – Name of the part
- Returns:
True if part has one or more registered interfaces
- register(interface: InterfaceVolume) None[source]
Register an interface volume.
- Parameters:
interface – InterfaceVolume to register
- Raises:
ValueError – If interface with same name already registered
- register_many(interfaces: List[InterfaceVolume]) None[source]
Register multiple interface volumes.
- Parameters:
interfaces – List of InterfaceVolume objects to register
- to_dict() Dict[str, Any][source]
Convert registry to dictionary for serialization.
- Returns:
Dictionary with all interfaces serialized
- unregister(name: str) InterfaceVolume | None[source]
Remove an interface from the registry.
- Parameters:
name – Interface name to remove
- Returns:
The removed interface, or None if not found
yapcad.collision.result module
Collision detection result data structures.
This module defines the CollisionResult dataclass and CollisionMethod enum that represent the output of collision detection operations.
Copyright (c) 2026 yapCAD contributors License: MIT
- class yapcad.collision.result.CollisionMethod(*values)[source]
Bases:
EnumMethod used for collision detection.
- BREP
Exact BREP boolean intersection (pythonocc)
- MESH
Mesh-based sampling and containment (trimesh)
- AABB
Axis-aligned bounding box check only
- FCL
Flexible Collision Library (via trimesh)
- UNKNOWN
Method not specified or hybrid approach
- AABB = 3
- BREP = 1
- FCL = 4
- MESH = 2
- UNKNOWN = 5
- class yapcad.collision.result.CollisionResult(part_a: str, part_b: str, collides: bool, method: CollisionMethod = CollisionMethod.UNKNOWN, intersection_volume: float | None = None, penetration_depth: float = 0.0, contact_points: Tuple[float, float, float]]=<factory>, compatible_interface: bool = False, interface_names: List[str] = <factory>, error_message: str = '', metadata: Dict[str, ~typing.Any]=<factory>)[source]
Bases:
objectResult of collision detection between two parts.
This dataclass captures all information about a collision check between two assembly parts, including whether they collide, the detection method used, collision metrics, and interface compatibility status.
- method
Detection method used (BREP, MESH, AABB, FCL)
- contact_points
List of contact/intersection points as (x, y, z) tuples
- compatible_interface
True if overlap is due to compatible interfaces (e.g., meshing gears with matching module/pressure angle)
- Type:
Example
>>> result = CollisionResult( ... part_a="SUN_GEAR", ... part_b="PLANET_GEAR_1", ... collides=True, ... method=CollisionMethod.BREP, ... intersection_volume=15.3, ... compatible_interface=True, ... interface_names=["sun_teeth", "planet_1_teeth"] ... ) >>> if result.collides and not result.compatible_interface: ... print(f"ERROR: Unintended collision between {result.part_a} and {result.part_b}") ... elif result.collides: ... print(f"OK: Expected overlap (gear mesh) between {result.part_a} and {result.part_b}")
Notes
collides=True with compatible_interface=True indicates expected overlap (e.g., gear teeth meshing, threads engaging)
collides=True with compatible_interface=False indicates an actual collision that needs to be resolved
intersection_volume and penetration_depth may be None/0 if not computed by the detection method used
- classmethod error(part_a: str, part_b: str, message: str) CollisionResult[source]
Factory for creating an error result.
- Parameters:
part_a – First part name
part_b – Second part name
message – Error message describing what went wrong
- Returns:
CollisionResult with error_message set
- classmethod from_dict(data: Dict[str, Any]) CollisionResult[source]
Create CollisionResult from dictionary.
- Parameters:
data – Dictionary with collision result data
- Returns:
CollisionResult instance
- property is_interface_overlap: bool
True if collision is due to compatible interface (expected overlap).
- method: CollisionMethod = 5
- classmethod no_collision(part_a: str, part_b: str, method: CollisionMethod = CollisionMethod.UNKNOWN) CollisionResult[source]
Factory for creating a no-collision result.
- Parameters:
part_a – First part name
part_b – Second part name
method – Detection method used
- Returns:
CollisionResult with collides=False
yapcad.collision.thread_interface module
Thread interface for screw thread engagement overlap.
This module defines the ThreadInterface class for representing screw thread engagement regions where controlled overlap is expected.
Copyright (c) 2026 yapCAD contributors License: MIT
- class yapcad.collision.thread_interface.ThreadClass(*values)[source]
Bases:
EnumThread fit classes per ISO 965-1.
Defines the tolerance grade for thread fits, affecting clearance/interference between mating threads.
- ISO_6H_6g
Standard fit (normal clearance)
- ISO_6G_6h
Close fit (reduced clearance)
- ISO_5H_4h
Tight fit (precision applications)
- ISO_5H_4h = '5H/4h'
- ISO_6G_6h = '6G/6h'
- ISO_6H_6g = '6H/6g'
- class yapcad.collision.thread_interface.ThreadInterface(name: str, part_name: str, center: Tuple[float, float, float]=(0.0, 0.0, 0.0), axis: Tuple[float, float, float]=(0.0, 0.0, 1.0), description: str = '', metadata: Dict[str, ~typing.Any]=<factory>, pitch: float = 0.5, major_diameter: float = 3.0, thread_type: ThreadType = ThreadType.ISO_METRIC, thread_class: ThreadClass = ThreadClass.ISO_6H_6g, engagement_length: float = 6.0, is_internal: bool = False)[source]
Bases:
InterfaceVolumeInterface volume for screw thread engagement.
Defines the region where external threads (bolt/screw) engage with internal threads (tapped hole/nut). Compatible threads must have matching pitch and diameter.
- thread_type
Thread standard (ISO_METRIC, UNC, etc.)
- thread_class
Fit class (tolerance grade)
- Derived Properties:
minor_diameter: Root diameter of external thread pitch_diameter: Diameter where thread flanks meet thread_depth: Radial depth of thread profile
- Common ISO Metric Threads:
M2: pitch=0.4mm, major=2.0mm M2.5: pitch=0.45mm, major=2.5mm M3: pitch=0.5mm, major=3.0mm M4: pitch=0.7mm, major=4.0mm M5: pitch=0.8mm, major=5.0mm M6: pitch=1.0mm, major=6.0mm
Example
>>> bolt = ThreadInterface.from_metric_size("M3", is_internal=False) >>> hole = ThreadInterface.from_metric_size("M3", is_internal=True) >>> result = bolt.check_compatibility(hole) >>> print(result) # COMPATIBLE: Threads compatible: M3.0x0.5
- check_compatibility(other: InterfaceVolume) CompatibilityResult[source]
Check if this thread can engage with another interface.
- Compatible conditions:
Other must be a ThreadInterface
One must be internal, one external
Major diameters must match (within 0.1% tolerance)
Pitches must match (within 0.1% tolerance)
Thread types should be compatible
- Parameters:
other – Another interface volume to check against
- Returns:
CompatibilityResult indicating if threads can properly engage
- classmethod from_metric_size(size: str, engagement_length: float = None, is_internal: bool = False, name: str = None, part_name: str = '', **kwargs) ThreadInterface[source]
Create ThreadInterface from metric size string.
- Parameters:
size – Metric size string (e.g., “M3”, “M2.5”, “M4x0.5”)
engagement_length – Thread engagement in mm (default: 1.5 * diameter)
is_internal – True for tapped hole
name – Interface name (default: “thread_{size}”)
part_name – Name of the part this interface belongs to
**kwargs – Additional arguments passed to constructor
- Returns:
ThreadInterface configured for the specified size
- Raises:
ValueError – If size string cannot be parsed
Example
>>> bolt = ThreadInterface.from_metric_size("M3", is_internal=False) >>> fine_bolt = ThreadInterface.from_metric_size("M4x0.5")
- get_bounding_cylinder() Tuple[float, float][source]
Get cylindrical bounding volume (radius, height).
- Returns:
Tuple of (radius, height) where radius is major_diameter/2 and height is engagement_length.
- get_engagement_depth() float[source]
Engagement length is the depth for threads.
- Returns:
Thread engagement length in mm
- interface_type: InterfaceType = 2
- property minor_diameter: float
Minor diameter (root of external thread).
Approximation for ISO metric: D_minor = D_major - 1.0825 * pitch
- property pitch_diameter: float
Pitch diameter (where thread flanks meet).
Approximation for ISO metric: D_pitch = D_major - 0.6495 * pitch
- thread_class: ThreadClass = '6H/6g'
- thread_type: ThreadType = 'ISO'
- class yapcad.collision.thread_interface.ThreadType(*values)[source]
Bases:
EnumStandard thread types.
- ISO_METRIC
ISO metric thread (M2, M3, M4, etc.)
- ISO_METRIC_FINE
ISO metric fine pitch thread
- UNC
Unified National Coarse (imperial)
- UNF
Unified National Fine (imperial)
- ACME
Trapezoidal/ACME thread for power transmission
- CUSTOM
User-defined thread profile
- ACME = 'ACME'
- CUSTOM = 'CUSTOM'
- ISO_METRIC = 'ISO'
- ISO_METRIC_FINE = 'ISO_F'
- UNC = 'UNC'
- UNF = 'UNF'
- yapcad.collision.thread_interface.create_bolt_pattern_interfaces(pattern_name: str, bolt_part_name: str, hole_part_name: str, thread_size: str, positions: List[Tuple[float, float, float]], engagement_length: float = None) List[ThreadInterface][source]
Create interface volumes for a bolt pattern.
Creates matching pairs of external (bolt) and internal (hole) thread interfaces at specified positions.
- Parameters:
pattern_name – Base name for the bolt pattern
bolt_part_name – Part containing the bolts
hole_part_name – Part containing the tapped holes
thread_size – Thread size (e.g., “M3”, “M2.5”)
positions – List of (x, y, z) positions for each bolt
engagement_length – Thread engagement in mm (default: from size)
- Returns:
List of ThreadInterface objects (bolts and holes)
Example
>>> positions = [(10, 0, 0), (-10, 0, 0), (0, 10, 0), (0, -10, 0)] >>> interfaces = create_bolt_pattern_interfaces( ... "mounting_bolts", ... "BRACKET", "BASE_PLATE", ... "M3", positions ... )
Module contents
Collision detection system for yapCAD assemblies.
This package provides collision detection capabilities for validating assembly configurations. It supports multiple detection methods with automatic fallback:
BREP-based detection (requires pythonocc-core): Uses exact boolean intersection via BRepAlgoAPI_Common for precise collision volumes. This is the most accurate method.
Mesh-based detection (requires trimesh): Uses point sampling and containment checks for collision detection. Works with STL/mesh geometry when BREP is unavailable.
AABB-based detection: Fast bounding box checks for quick rejection of non-colliding pairs. Always available as a first-pass filter.
- Key Features:
Pluggable geometry source via GeometryProvider protocol
Interface volume system for allowed overlaps (gear mesh, threads, etc.)
Detailed collision results with volumes, penetration depths, contact points
Integration with assembly constraint system
- Design Principles:
No hardcoded part-to-file mappings (use GeometryProvider)
No project-specific exclusion lists (use InterfaceRegistry)
Works with any assembly via pluggable interfaces
Graceful degradation when optional dependencies unavailable
- Quick Start:
>>> from yapcad.collision import ( ... CollisionDetector, ... CollisionResult, ... InterfaceRegistry, ... GearMeshInterface, ... ) >>> >>> # Create detector with geometry provider >>> class MyGeometryProvider: ... def get_geometry(self, part_name: str) -> Optional[Any]: ... # Return STEP/STL path or mesh object ... return f"parts/{part_name}.step" ... >>> detector = CollisionDetector(MyGeometryProvider()) >>> >>> # Register allowed overlaps for gear meshing >>> registry = InterfaceRegistry() >>> registry.register(GearMeshInterface( ... name="sun_teeth", part_name="SUN_GEAR", ... module=0.75, teeth=18, pressure_angle=20.0, face_width=10.0 ... )) >>> detector.set_interface_registry(registry) >>> >>> # Check assembly for collisions >>> world_transforms = {"SUN_GEAR": tf1, "PLANET_GEAR": tf2, ...} >>> results = detector.check_assembly(world_transforms) >>> for result in results: ... if result.collides and not result.compatible_interface: ... print(f"COLLISION: {result.part_a} <-> {result.part_b}")
- Available Classes:
- Detection:
CollisionDetector - Main collision detection class CollisionResult - Detailed collision result data GeometryProvider - Protocol for geometry source
- Interface Volumes (allowed overlaps):
InterfaceVolume - Base class for interface volumes InterfaceType - Enum of interface types GearMeshInterface - Gear teeth meshing interface ThreadInterface - Screw thread engagement interface InterfaceRegistry - Registry for managing interfaces
See also
yapcad.assembly: Constraint-based assembly system
yapcad.octtree: Spatial indexing for acceleration
Collision detection system contributed by Jeremy Mika.
Copyright (c) 2026 yapCAD contributors License: MIT
- class yapcad.collision.CollisionDetector(geometry_provider: GeometryProvider, interface_registry: InterfaceRegistry | None = None, verbose: bool = False, min_collision_volume: float = 0.1, mesh_sample_points: int = 1500, penetration_threshold: float = 0.1)[source]
Bases:
objectMain collision detection class with multiple detection methods.
CollisionDetector provides collision detection between assembly parts using the best available method:
BREP detection (if pythonocc available): Uses boolean intersection for exact collision volume
Mesh detection (if trimesh available): Uses point sampling and containment checks
AABB detection (always available): Fast bounding box checks (used as pre-filter)
The detector integrates with InterfaceRegistry to distinguish expected overlaps (gear mesh, threads) from actual collisions.
- geometry_provider
Provider for part geometry
- interface_registry
Registry of allowed overlap interfaces
- verbose
Enable detailed logging
- min_collision_volume
Minimum volume to report (mm^3)
- mesh_sample_points
Number of sample points for mesh detection
- penetration_threshold
Minimum depth to count as collision (mm)
Example
>>> provider = MyGeometryProvider() >>> detector = CollisionDetector(provider) >>> >>> # Optional: register allowed overlaps >>> registry = InterfaceRegistry() >>> registry.register(GearMeshInterface(...)) >>> detector.set_interface_registry(registry) >>> >>> # Check single pair >>> result = detector.check_collision( ... "PART_A", transform_a, ... "PART_B", transform_b ... ) >>> >>> # Check full assembly >>> transforms = {"PART_A": tf_a, "PART_B": tf_b, "PART_C": tf_c} >>> results = detector.check_assembly(transforms) >>> collisions = [r for r in results if r.is_error]
- check_assembly(world_transforms: Dict[str, Any], skip_pairs: List[Tuple[str, str]] | None = None) List[CollisionResult][source]
Check all pairs in an assembly for collisions.
- Parameters:
world_transforms – Dictionary mapping part names to 4x4 transforms
skip_pairs – Optional list of (part_a, part_b) pairs to skip
- Returns:
List of CollisionResult for all pairs checked
- check_collision(part_a: str, transform_a: Any, part_b: str, transform_b: Any, method: CollisionMethod | None = None) CollisionResult[source]
Check for collision between two parts.
- Parameters:
part_a – Name of first part
transform_a – 4x4 transformation matrix for part A
part_b – Name of second part
transform_b – 4x4 transformation matrix for part B
method – Specific detection method (default: best available)
- Returns:
CollisionResult with collision details
- get_collision_summary(results: List[CollisionResult]) Dict[str, Any][source]
Generate summary statistics from collision results.
- Parameters:
results – List of CollisionResult from check_assembly
- Returns:
Dictionary with summary statistics
- property preferred_method: CollisionMethod
Get the preferred detection method based on available libraries.
- set_interface_registry(registry: InterfaceRegistry) None[source]
Set the interface registry for allowed overlaps.
- Parameters:
registry – InterfaceRegistry with interface definitions
- class yapcad.collision.CollisionMethod(*values)[source]
Bases:
EnumMethod used for collision detection.
- BREP
Exact BREP boolean intersection (pythonocc)
- MESH
Mesh-based sampling and containment (trimesh)
- AABB
Axis-aligned bounding box check only
- FCL
Flexible Collision Library (via trimesh)
- UNKNOWN
Method not specified or hybrid approach
- AABB = 3
- BREP = 1
- FCL = 4
- MESH = 2
- UNKNOWN = 5
- class yapcad.collision.CollisionResult(part_a: str, part_b: str, collides: bool, method: CollisionMethod = CollisionMethod.UNKNOWN, intersection_volume: float | None = None, penetration_depth: float = 0.0, contact_points: Tuple[float, float, float]]=<factory>, compatible_interface: bool = False, interface_names: List[str] = <factory>, error_message: str = '', metadata: Dict[str, ~typing.Any]=<factory>)[source]
Bases:
objectResult of collision detection between two parts.
This dataclass captures all information about a collision check between two assembly parts, including whether they collide, the detection method used, collision metrics, and interface compatibility status.
- method
Detection method used (BREP, MESH, AABB, FCL)
- contact_points
List of contact/intersection points as (x, y, z) tuples
- compatible_interface
True if overlap is due to compatible interfaces (e.g., meshing gears with matching module/pressure angle)
- Type:
Example
>>> result = CollisionResult( ... part_a="SUN_GEAR", ... part_b="PLANET_GEAR_1", ... collides=True, ... method=CollisionMethod.BREP, ... intersection_volume=15.3, ... compatible_interface=True, ... interface_names=["sun_teeth", "planet_1_teeth"] ... ) >>> if result.collides and not result.compatible_interface: ... print(f"ERROR: Unintended collision between {result.part_a} and {result.part_b}") ... elif result.collides: ... print(f"OK: Expected overlap (gear mesh) between {result.part_a} and {result.part_b}")
Notes
collides=True with compatible_interface=True indicates expected overlap (e.g., gear teeth meshing, threads engaging)
collides=True with compatible_interface=False indicates an actual collision that needs to be resolved
intersection_volume and penetration_depth may be None/0 if not computed by the detection method used
- classmethod error(part_a: str, part_b: str, message: str) CollisionResult[source]
Factory for creating an error result.
- Parameters:
part_a – First part name
part_b – Second part name
message – Error message describing what went wrong
- Returns:
CollisionResult with error_message set
- classmethod from_dict(data: Dict[str, Any]) CollisionResult[source]
Create CollisionResult from dictionary.
- Parameters:
data – Dictionary with collision result data
- Returns:
CollisionResult instance
- property is_interface_overlap: bool
True if collision is due to compatible interface (expected overlap).
- method: CollisionMethod = 5
- classmethod no_collision(part_a: str, part_b: str, method: CollisionMethod = CollisionMethod.UNKNOWN) CollisionResult[source]
Factory for creating a no-collision result.
- Parameters:
part_a – First part name
part_b – Second part name
method – Detection method used
- Returns:
CollisionResult with collides=False
- class yapcad.collision.CompatibilityResult(is_compatible: bool, reason: str, warnings: List[str] = <factory>, overlap_volume: float = 0.0, required_clearance: float = 0.0)[source]
Bases:
objectResult of checking interface compatibility.
When two interface volumes overlap, this result indicates whether they are designed to mate properly (compatible) or represent an unintended collision (incompatible).
Example
>>> result = sun_gear.check_compatibility(planet_gear) >>> if result.is_compatible: ... print(f"Gears can mesh: {result.reason}") ... if result.warnings: ... print(f"Warnings: {result.warnings}") ... else: ... print(f"Incompatible: {result.reason}")
- class yapcad.collision.GearMeshInterface(name: str, part_name: str, center: Tuple[float, float, float]=(0.0, 0.0, 0.0), axis: Tuple[float, float, float]=(0.0, 0.0, 1.0), description: str = '', metadata: Dict[str, ~typing.Any]=<factory>, module: float = 1.0, teeth: int = 20, pressure_angle: float = 20.0, face_width: float = 10.0, helix_angle: float = 0.0, backlash: float = 0.0)[source]
Bases:
InterfaceVolumeInterface volume for involute gear teeth meshing.
Defines the region where gear teeth overlap during meshing. Two gears are compatible if they have the same module and pressure angle (standard involute tooth profile).
- Derived Properties:
pitch_diameter: module * teeth addendum: module (tooth height above pitch circle) dedendum: 1.25 * module (tooth depth below pitch circle) outside_diameter: pitch_diameter + 2 * addendum root_diameter: pitch_diameter - 2 * dedendum base_diameter: pitch_diameter * cos(pressure_angle)
Example
>>> sun = GearMeshInterface( ... name="sun_teeth", part_name="SUN_GEAR", ... module=0.75, teeth=18, pressure_angle=20.0, face_width=10.0 ... ) >>> planet = GearMeshInterface( ... name="planet_teeth", part_name="PLANET_GEAR", ... module=0.75, teeth=36, pressure_angle=20.0, face_width=10.0 ... ) >>> result = sun.check_compatibility(planet) >>> print(result) # COMPATIBLE: Gears compatible: m=0.75mm, PA=20.0deg >>> print(f"Center distance: {sun.get_center_distance(planet):.2f}mm")
Notes
Module must match exactly between meshing gears (within 0.1% tolerance)
Pressure angle must match (within 0.5 degree tolerance)
For helical gears, helix angles must be opposite (LH + RH = 0)
Face widths must have sufficient overlap for load transfer
- check_compatibility(other: InterfaceVolume) CompatibilityResult[source]
Check if this gear can mesh with another interface.
- Compatible conditions:
Other must be a GearMeshInterface
Modules must match (within 0.1% tolerance)
Pressure angles must match (within 0.5 degree tolerance)
Helix angles must be compatible (opposite for external mesh)
Face widths must have sufficient overlap
- Parameters:
other – Another interface volume to check against
- Returns:
CompatibilityResult indicating if gears can properly mesh
- get_bounding_cylinder() Tuple[float, float][source]
Get cylindrical bounding volume (radius, height).
- Returns:
Tuple of (radius, height) where radius extends to outside diameter and height is the face width.
- get_center_distance(other: GearMeshInterface) float[source]
Calculate theoretical center distance for meshing with another gear.
- Parameters:
other – Another gear to mesh with
- Returns:
Center-to-center distance for proper meshing in mm
- Raises:
ValueError – If modules don’t match
- get_engagement_depth() float[source]
Face width is the engagement depth for gears.
- Returns:
Face width in mm
- get_expected_overlap_volume(other: GearMeshInterface) float[source]
Calculate expected overlap volume when meshing with another gear.
This provides an estimate of how much volume the gear teeth should overlap when properly meshed, useful for validating collision detection results.
- Parameters:
other – Another gear to mesh with
- Returns:
Estimated overlap volume in mm^3
- get_mesh_overlap_depth() float[source]
Calculate the theoretical tooth mesh overlap depth.
This is the radial depth where teeth from two meshing gears actually overlap, used for collision solver exceptions.
- Returns:
Depth of tooth engagement zone in mm (approximately 2 * module)
- interface_type: InterfaceType = 1
- class yapcad.collision.GeometryProvider(*args, **kwargs)[source]
Bases:
ProtocolProtocol for providing geometry data for collision detection.
Implementations must provide a way to retrieve geometry for parts by name. The geometry can be returned as:
Path to STEP file (preferred for BREP detection)
Path to STL file (for mesh detection)
trimesh.Trimesh object (pre-loaded mesh)
TopoDS_Shape object (pre-loaded BREP)
Example
>>> class FileBasedProvider: ... def __init__(self, base_dir: Path): ... self.base_dir = base_dir ... ... def get_geometry(self, part_name: str) -> Optional[str]: ... step_path = self.base_dir / f"{part_name}.step" ... if step_path.exists(): ... return str(step_path) ... stl_path = self.base_dir / f"{part_name}.stl" ... if stl_path.exists(): ... return str(stl_path) ... return None
- class yapcad.collision.InterfaceRegistry[source]
Bases:
objectRegistry for managing interface volumes in an assembly.
The registry tracks all interface volumes and provides lookup methods for the collision detector to find compatible interfaces when overlap is detected between parts.
- Key Features:
Register/unregister interface volumes by name
Query interfaces by part name or interface type
Check overlap compatibility between parts
Find all compatible interfaces for a given interface
- Usage:
>>> registry = InterfaceRegistry() >>> >>> # Register gear interfaces >>> registry.register(GearMeshInterface( ... name="sun_teeth", part_name="SUN_GEAR", ... module=0.75, teeth=18, pressure_angle=20.0, face_width=10.0 ... )) >>> registry.register(GearMeshInterface( ... name="planet_teeth", part_name="PLANET_GEAR", ... module=0.75, teeth=36, pressure_angle=20.0, face_width=10.0 ... )) >>> >>> # During collision detection >>> is_compatible, results = registry.check_overlap_compatibility( ... "SUN_GEAR", "PLANET_GEAR" ... ) >>> if is_compatible: ... print("Overlap is expected (gear mesh)")
Notes
Interface names must be unique within the registry
Parts can have multiple interfaces (e.g., gear teeth + bearing seat)
The registry does not store geometry, only interface definitions
- check_overlap_compatibility(part_a: str, part_b: str, overlap_region: Tuple[Any, Any] | None = None) Tuple[bool, List[CompatibilityResult]][source]
Check if overlap between two parts is due to compatible interfaces.
This is the main entry point for the collision detector to check whether detected overlap should be allowed (expected interface) or flagged as a collision error.
- Parameters:
part_a – First part name
part_b – Second part name
overlap_region – Optional (center, size) of overlap bounding box for spatial filtering (not yet implemented)
- Returns:
bool: True if ALL overlapping interfaces are compatible
List[CompatibilityResult]: Results for each interface pair checked
- Return type:
Tuple of
Example
>>> is_ok, results = registry.check_overlap_compatibility("SUN", "PLANET") >>> if is_ok: ... print("Expected gear mesh overlap") ... else: ... for r in results: ... if not r.is_compatible: ... print(f"Incompatible: {r.reason}")
- find_compatible_interfaces(interface: InterfaceVolume, candidates: List[InterfaceVolume] = None) List[Tuple[InterfaceVolume, CompatibilityResult]][source]
Find all interfaces compatible with the given interface.
- Parameters:
interface – Interface to find matches for
candidates – List of candidates to check (default: all registered)
- Returns:
List of (interface, compatibility_result) tuples for compatible interfaces
- get(name: str) InterfaceVolume | None[source]
Get interface by name.
- Parameters:
name – Interface name to look up
- Returns:
InterfaceVolume if found, None otherwise
- get_all_interfaces() List[InterfaceVolume][source]
Get all registered interfaces.
- Returns:
List of all InterfaceVolume objects in the registry
- get_all_parts() List[str][source]
Get names of all parts with registered interfaces.
- Returns:
List of part names
- get_compatible_interface_names(part_a: str, part_b: str) List[str][source]
Get names of compatible interfaces between two parts.
Convenience method to get just the interface names for parts that have compatible overlap.
- Parameters:
part_a – First part name
part_b – Second part name
- Returns:
List of compatible interface names (from both parts)
- get_interfaces_by_type(interface_type: InterfaceType) List[InterfaceVolume][source]
Get all interfaces of a specific type.
- Parameters:
interface_type – Type of interface to find
- Returns:
List of matching InterfaceVolume objects (may be empty)
- get_interfaces_for_part(part_name: str) List[InterfaceVolume][source]
Get all interfaces belonging to a part.
- Parameters:
part_name – Name of the part
- Returns:
List of InterfaceVolume objects for the part (may be empty)
- has_interfaces(part_name: str) bool[source]
Check if a part has any registered interfaces.
- Parameters:
part_name – Name of the part
- Returns:
True if part has one or more registered interfaces
- register(interface: InterfaceVolume) None[source]
Register an interface volume.
- Parameters:
interface – InterfaceVolume to register
- Raises:
ValueError – If interface with same name already registered
- register_many(interfaces: List[InterfaceVolume]) None[source]
Register multiple interface volumes.
- Parameters:
interfaces – List of InterfaceVolume objects to register
- to_dict() Dict[str, Any][source]
Convert registry to dictionary for serialization.
- Returns:
Dictionary with all interfaces serialized
- unregister(name: str) InterfaceVolume | None[source]
Remove an interface from the registry.
- Parameters:
name – Interface name to remove
- Returns:
The removed interface, or None if not found
- class yapcad.collision.InterfaceType(*values)[source]
Bases:
EnumTypes of interface volumes for controlled overlap.
Each type represents a specific mechanical interface where geometric overlap is expected and designed.
- GEAR_MESH
Involute gear teeth meshing
- THREAD
Screw thread engagement (bolt/nut, tap/screw)
- PRESS_FIT
Interference fit (shaft/bore)
- BEARING
Bearing race contact regions
- SPLINE
Spline coupling interface
- KEY
Key/keyway interface
- SNAP_FIT
Snap-fit detent mechanism
- CUSTOM
User-defined interface type
- BEARING = 4
- CUSTOM = 8
- GEAR_MESH = 1
- KEY = 6
- PRESS_FIT = 3
- SNAP_FIT = 7
- SPLINE = 5
- THREAD = 2
- class yapcad.collision.InterfaceVolume(name: str, part_name: str, interface_type: InterfaceType, center: Tuple[float, float, float]=(0.0, 0.0, 0.0), axis: Tuple[float, float, float]=(0.0, 0.0, 1.0), description: str = '', metadata: Dict[str, ~typing.Any]=<factory>)[source]
Bases:
ABCBase class for interface volumes that allow controlled overlap.
Interface volumes define regions where parts are DESIGNED to overlap, such as gear teeth meshing, threads engaging, or press fits. The collision detector uses these to distinguish expected overlap from actual collisions.
- Subclasses must implement:
get_bounding_cylinder(): Return (radius, height) of enclosing cylinder
check_compatibility(): Check if another interface can mate properly
get_engagement_depth(): Return the engagement/overlap depth
- interface_type
Type of interface (GEAR_MESH, THREAD, etc.)
- axis
Primary axis direction as (x, y, z) tuple (rotation/engagement axis)
Example
>>> class MyInterface(InterfaceVolume): ... def get_bounding_cylinder(self): ... return (10.0, 5.0) # radius=10mm, height=5mm ... def check_compatibility(self, other): ... if isinstance(other, MyInterface): ... return CompatibilityResult(True, "Compatible") ... return CompatibilityResult(False, "Type mismatch") ... def get_engagement_depth(self): ... return 5.0
- abstractmethod check_compatibility(other: InterfaceVolume) CompatibilityResult[source]
Check if this interface is compatible with another.
Two interfaces are compatible if they are designed to mate properly when overlapping (e.g., matching gear modules, matching thread pitches).
- Parameters:
other – Another interface volume to check against
- Returns:
CompatibilityResult indicating if interfaces can properly mate
- abstractmethod get_bounding_cylinder() Tuple[float, float][source]
Get cylindrical bounding volume for the interface.
- Returns:
Tuple of (radius, height) in mm defining the minimum enclosing cylinder aligned with the interface axis.
- abstractmethod get_engagement_depth() float[source]
Get the depth/length of interface engagement in mm.
- For different interface types:
Gears: face width
Threads: engagement length
Press fits: engagement length
Bearings: bearing width
- Returns:
Engagement depth in mm
- interface_type: InterfaceType
- overlaps_with(other: InterfaceVolume, tolerance: float = 0.1) bool[source]
Check if two interface volumes spatially overlap.
This is a geometric overlap check, not a compatibility check. Two interfaces can overlap geometrically but be incompatible (e.g., mismatched gear modules).
- Parameters:
other – Another interface volume to check
tolerance – Distance tolerance for overlap detection in mm
- Returns:
True if bounding volumes overlap within tolerance
- to_dict() Dict[str, Any][source]
Convert to dictionary for serialization.
- Returns:
Dictionary representation suitable for JSON export
- class yapcad.collision.ThreadClass(*values)[source]
Bases:
EnumThread fit classes per ISO 965-1.
Defines the tolerance grade for thread fits, affecting clearance/interference between mating threads.
- ISO_6H_6g
Standard fit (normal clearance)
- ISO_6G_6h
Close fit (reduced clearance)
- ISO_5H_4h
Tight fit (precision applications)
- ISO_5H_4h = '5H/4h'
- ISO_6G_6h = '6G/6h'
- ISO_6H_6g = '6H/6g'
- class yapcad.collision.ThreadInterface(name: str, part_name: str, center: Tuple[float, float, float]=(0.0, 0.0, 0.0), axis: Tuple[float, float, float]=(0.0, 0.0, 1.0), description: str = '', metadata: Dict[str, ~typing.Any]=<factory>, pitch: float = 0.5, major_diameter: float = 3.0, thread_type: ThreadType = ThreadType.ISO_METRIC, thread_class: ThreadClass = ThreadClass.ISO_6H_6g, engagement_length: float = 6.0, is_internal: bool = False)[source]
Bases:
InterfaceVolumeInterface volume for screw thread engagement.
Defines the region where external threads (bolt/screw) engage with internal threads (tapped hole/nut). Compatible threads must have matching pitch and diameter.
- thread_type
Thread standard (ISO_METRIC, UNC, etc.)
- thread_class
Fit class (tolerance grade)
- Derived Properties:
minor_diameter: Root diameter of external thread pitch_diameter: Diameter where thread flanks meet thread_depth: Radial depth of thread profile
- Common ISO Metric Threads:
M2: pitch=0.4mm, major=2.0mm M2.5: pitch=0.45mm, major=2.5mm M3: pitch=0.5mm, major=3.0mm M4: pitch=0.7mm, major=4.0mm M5: pitch=0.8mm, major=5.0mm M6: pitch=1.0mm, major=6.0mm
Example
>>> bolt = ThreadInterface.from_metric_size("M3", is_internal=False) >>> hole = ThreadInterface.from_metric_size("M3", is_internal=True) >>> result = bolt.check_compatibility(hole) >>> print(result) # COMPATIBLE: Threads compatible: M3.0x0.5
- check_compatibility(other: InterfaceVolume) CompatibilityResult[source]
Check if this thread can engage with another interface.
- Compatible conditions:
Other must be a ThreadInterface
One must be internal, one external
Major diameters must match (within 0.1% tolerance)
Pitches must match (within 0.1% tolerance)
Thread types should be compatible
- Parameters:
other – Another interface volume to check against
- Returns:
CompatibilityResult indicating if threads can properly engage
- classmethod from_metric_size(size: str, engagement_length: float = None, is_internal: bool = False, name: str = None, part_name: str = '', **kwargs) ThreadInterface[source]
Create ThreadInterface from metric size string.
- Parameters:
size – Metric size string (e.g., “M3”, “M2.5”, “M4x0.5”)
engagement_length – Thread engagement in mm (default: 1.5 * diameter)
is_internal – True for tapped hole
name – Interface name (default: “thread_{size}”)
part_name – Name of the part this interface belongs to
**kwargs – Additional arguments passed to constructor
- Returns:
ThreadInterface configured for the specified size
- Raises:
ValueError – If size string cannot be parsed
Example
>>> bolt = ThreadInterface.from_metric_size("M3", is_internal=False) >>> fine_bolt = ThreadInterface.from_metric_size("M4x0.5")
- get_bounding_cylinder() Tuple[float, float][source]
Get cylindrical bounding volume (radius, height).
- Returns:
Tuple of (radius, height) where radius is major_diameter/2 and height is engagement_length.
- get_engagement_depth() float[source]
Engagement length is the depth for threads.
- Returns:
Thread engagement length in mm
- interface_type: InterfaceType = 2
- property minor_diameter: float
Minor diameter (root of external thread).
Approximation for ISO metric: D_minor = D_major - 1.0825 * pitch
- property pitch_diameter: float
Pitch diameter (where thread flanks meet).
Approximation for ISO metric: D_pitch = D_major - 0.6495 * pitch
- thread_class: ThreadClass = '6H/6g'
- thread_type: ThreadType = 'ISO'
- class yapcad.collision.ThreadType(*values)[source]
Bases:
EnumStandard thread types.
- ISO_METRIC
ISO metric thread (M2, M3, M4, etc.)
- ISO_METRIC_FINE
ISO metric fine pitch thread
- UNC
Unified National Coarse (imperial)
- UNF
Unified National Fine (imperial)
- ACME
Trapezoidal/ACME thread for power transmission
- CUSTOM
User-defined thread profile
- ACME = 'ACME'
- CUSTOM = 'CUSTOM'
- ISO_METRIC = 'ISO'
- ISO_METRIC_FINE = 'ISO_F'
- UNC = 'UNC'
- UNF = 'UNF'
- yapcad.collision.check_gear_mesh_collision(gear_a: GearMeshInterface, gear_b: GearMeshInterface, actual_center_distance: float, tolerance: float = 0.1) CompatibilityResult[source]
Check if two gears are correctly positioned for meshing.
This function verifies both gear compatibility and proper positioning by comparing actual center distance to theoretical.
- Parameters:
gear_a – First gear interface
gear_b – Second gear interface
actual_center_distance – Measured center-to-center distance in mm
tolerance – Allowable deviation from theoretical in mm
- Returns:
CompatibilityResult with mesh status and any warnings
Example
>>> sun = GearMeshInterface(name="sun", part_name="SUN", module=0.75, teeth=18) >>> planet = GearMeshInterface(name="planet", part_name="PLANET", module=0.75, teeth=36) >>> result = check_gear_mesh_collision(sun, planet, actual_center_distance=20.25) >>> if result.is_compatible: ... print("Gears properly meshed")
- yapcad.collision.create_planetary_gearbox_interfaces(gearbox_name: str, module: float, sun_teeth: int, planet_teeth: int, ring_teeth: int, face_width: float, num_planets: int = 3, pressure_angle: float = 20.0, mesh_plane_z: float = 0.0) List[GearMeshInterface][source]
Create interface volumes for a complete planetary gearbox.
This factory function creates GearMeshInterface objects for all gears in a planetary gearbox configuration: one sun, one ring, and multiple planet gears at the correct orbital positions.
- Parameters:
gearbox_name – Base name for the gearbox (e.g., “AXIS1”)
module – Gear module in mm
sun_teeth – Number of teeth on sun gear
planet_teeth – Number of teeth on planet gears
ring_teeth – Number of teeth on ring gear (internal)
face_width – Gear face width in mm
num_planets – Number of planet gears (typically 3)
pressure_angle – Pressure angle in degrees (typically 20.0)
mesh_plane_z – Z coordinate of the gear mesh plane
- Returns:
List of GearMeshInterface objects for all gears
Example
>>> interfaces = create_planetary_gearbox_interfaces( ... gearbox_name="AXIS1", ... module=0.75, ... sun_teeth=18, ... planet_teeth=36, ... ring_teeth=90, ... face_width=10.0, ... num_planets=3 ... ) >>> for iface in interfaces: ... print(f"{iface.name}: {iface.teeth}T at {iface.center}")
Notes
Verifies planetary gear geometry: ring_teeth = sun_teeth + 2 * planet_teeth
Places planets at equal angular intervals
All gears centered at Z = mesh_plane_z