mirror of
https://github.com/johndoe6345789/bamboogenerator.git
synced 2026-04-24 13:24:54 +00:00
Add chain sprocket primitive and example
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
output/
|
||||
*.log
|
||||
|
||||
@@ -3,7 +3,16 @@
|
||||
from .core import tm, safe_difference
|
||||
from .primitives.box import Box
|
||||
from .primitives.gear import SpurGear
|
||||
from .primitives.sprocket import ChainSprocket
|
||||
from .mechanisms.butthinge import ButtHinge
|
||||
from .export.stl import STLExporter
|
||||
|
||||
__all__ = ["tm", "safe_difference", "Box", "SpurGear", "ButtHinge", "STLExporter"]
|
||||
__all__ = [
|
||||
"tm",
|
||||
"safe_difference",
|
||||
"Box",
|
||||
"SpurGear",
|
||||
"ChainSprocket",
|
||||
"ButtHinge",
|
||||
"STLExporter",
|
||||
]
|
||||
|
||||
10
parametric_cad/examples/sprocket_example.py
Normal file
10
parametric_cad/examples/sprocket_example.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from parametric_cad.primitives.sprocket import ChainSprocket
|
||||
from parametric_cad.export.stl import STLExporter
|
||||
|
||||
# Example sprocket for #420 chain (pitch 12.7 mm, roller dia ~7.75 mm)
|
||||
|
||||
sprocket = ChainSprocket(pitch=12.7, roller_diameter=7.75, teeth=14,
|
||||
thickness=6.0, bore_diameter=25.0)
|
||||
|
||||
exporter = STLExporter(output_dir="output/sprocket_example_output")
|
||||
exporter.export_mesh(sprocket.mesh(), "sprocket")
|
||||
56
parametric_cad/primitives/sprocket.py
Normal file
56
parametric_cad/primitives/sprocket.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from math import cos, sin, pi
|
||||
from parametric_cad.core import tm, safe_difference
|
||||
|
||||
class ChainSprocket:
|
||||
"""Simple chain sprocket for roller chain."""
|
||||
|
||||
def __init__(self, pitch=12.7, roller_diameter=7.75, teeth=16,
|
||||
thickness=5.0, bore_diameter=10.0, clearance=0.5):
|
||||
self.pitch = float(pitch)
|
||||
self.roller_diameter = float(roller_diameter)
|
||||
self.teeth = int(teeth)
|
||||
self.thickness = float(thickness)
|
||||
self.bore_diameter = float(bore_diameter)
|
||||
self.clearance = float(clearance)
|
||||
|
||||
@property
|
||||
def pitch_radius(self):
|
||||
return self.pitch / (2 * sin(pi / self.teeth))
|
||||
|
||||
@property
|
||||
def pitch_diameter(self):
|
||||
return self.pitch_radius * 2
|
||||
|
||||
def mesh(self):
|
||||
# Base disc sized so pockets can be subtracted
|
||||
outer_radius = self.pitch_radius + self.roller_diameter / 2 + self.clearance
|
||||
disc = tm.creation.cylinder(radius=outer_radius, height=self.thickness,
|
||||
sections=self.teeth * 4)
|
||||
|
||||
disc.apply_translation([0, 0, self.thickness / 2])
|
||||
|
||||
bore = tm.creation.cylinder(radius=self.bore_diameter / 2,
|
||||
height=self.thickness + 0.1)
|
||||
bore.apply_translation([0, 0, self.thickness / 2])
|
||||
sprocket = safe_difference(disc, bore)
|
||||
|
||||
pocket_radius = self.roller_diameter / 2 + self.clearance
|
||||
pockets = []
|
||||
for i in range(self.teeth):
|
||||
angle = 2 * pi * i / self.teeth
|
||||
x = cos(angle) * self.pitch_radius
|
||||
y = sin(angle) * self.pitch_radius
|
||||
pocket = tm.creation.cylinder(radius=pocket_radius,
|
||||
height=self.thickness + 0.1,
|
||||
sections=16)
|
||||
pocket.apply_translation([x, y, self.thickness / 2])
|
||||
pockets.append(pocket)
|
||||
|
||||
sprocket = safe_difference(sprocket, pockets)
|
||||
if not sprocket.is_watertight:
|
||||
repaired = sprocket.fill_holes()
|
||||
if repaired is not False:
|
||||
sprocket = repaired
|
||||
else:
|
||||
sprocket = sprocket.convex_hull
|
||||
return sprocket
|
||||
@@ -49,11 +49,12 @@ if __name__ == "__main__":
|
||||
logging.debug("Starting run_examples.py execution")
|
||||
set_environment()
|
||||
|
||||
examples = [
|
||||
"box_with_door.py",
|
||||
"hollow_box.py",
|
||||
"spur_gear_example.py"
|
||||
]
|
||||
examples = [
|
||||
"box_with_door.py",
|
||||
"hollow_box.py",
|
||||
"spur_gear_example.py",
|
||||
"sprocket_example.py",
|
||||
]
|
||||
|
||||
for example in examples:
|
||||
run_example_script(example)
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import pytest
|
||||
import numpy as np
|
||||
from parametric_cad.core import tm, safe_difference
|
||||
from math import cos, pi
|
||||
from math import cos, sin, pi
|
||||
|
||||
from parametric_cad.primitives.box import Box
|
||||
from parametric_cad.primitives.gear import SpurGear
|
||||
from parametric_cad.primitives.cylinder import Cylinder
|
||||
from parametric_cad.primitives.sphere import Sphere
|
||||
from parametric_cad.primitives.sprocket import ChainSprocket
|
||||
|
||||
|
||||
def test_box_mesh_extents_and_position():
|
||||
@@ -41,3 +42,12 @@ def test_safe_difference_returns_mesh():
|
||||
inner = Box(0.5, 0.5, 0.5).at(0.25, 0.25, 0.25)
|
||||
result = safe_difference(outer.mesh(), inner.mesh(), engine="invalid")
|
||||
assert isinstance(result, tm.Trimesh)
|
||||
|
||||
|
||||
def test_chain_sprocket_properties_and_mesh():
|
||||
sprocket = ChainSprocket(pitch=12.7, roller_diameter=7.75, teeth=10)
|
||||
expected_pitch_dia = 2 * sprocket.pitch / (2 * sin(pi / sprocket.teeth))
|
||||
assert sprocket.pitch_diameter == pytest.approx(expected_pitch_dia)
|
||||
mesh = sprocket.mesh()
|
||||
assert isinstance(mesh, tm.Trimesh)
|
||||
assert mesh.is_watertight
|
||||
|
||||
Reference in New Issue
Block a user