import cadquery as cq
import cadkit as ck
import math

# Parameters
MODULE = 2.0               # Module of the gear teeth
TEETH_COUNT = 60            # Number of teeth for the 120mm length (120 / (2*M))
LENGTH = 120.0             # Total length of the rack
SECTION_W = 20.0           # Width of the rack section
SECTION_H = 20.0           # Height of the rack section
HOLE_D = 6.5               # Clearance hole diameter for mounting
HOLE_DIST = 80.0            # Distance between mounting holes
HOLE_OFFSET_Y = 0.0         # Centered on Y axis

# Calculate gear geometry
# Pitch diameter for a rack is infinite, but we use gear_profile to get the tooth shape
# The pitch of a rack is pi * module
pitch = math.pi * MODULE
tooth_height = 2.25 * MODULE # Standard tooth height (addendum + dedendum)

# Create the base profile of the rack
rack_base = (
    cq.Workplane("XY")
    .box(LENGTH, SECTION_W, SECTION_H, centered=(True, True, False))
)

# Generate the tooth profile using cadkit's gear_profile
# We take a slice of a gear with a very large number of teeth to approximate a rack
# Or more simply, we can construct the tooth geometry manually based on the module
# For a rack: tooth width at pitch line is (pi * M) / 2
tooth_w = (math.pi * MODULE) / 2
addendum = MODULE
dedendum = 1.25 * MODULE

# Create a single tooth cutter
# Tooth shape: trapezoidal approximation of involute
tooth_cutter = (
    cq.Workplane("XY")
    .center(0, SECTION_H / 2)
    .polyline([
        (-tooth_w/2, -dedendum),
        (-tooth_w/2 + 0.2, 0), # slight taper
        (-tooth_w/2 + 0.5, addendum),
        (tooth_w/2 - 0.5, addendum),
        (tooth_w/2 - 0.2, 0),
        (tooth_w/2, -dedendum),
    ])
    .close()
    .extrude(SECTION_W, both=True)
)

# Create the rack by subtracting tooth gaps or adding teeth
# Better approach for a rack: start with a block and cut the gaps
gap_w = tooth_w # Simplified gap width
gap_depth = dedendum + addendum

# Create a gap cutter
gap_cutter = (
    cq.Workplane("XY")
    .center(0, SECTION_H / 2)
    .box(gap_w, SECTION_W, gap_depth + 1, centered=(True, True, False))
    .translate((0, 0, SECTION_H - gap_depth))
)

# Position the gaps along the length
# Start offset to center the rack
start_x = -LENGTH / 2 + (pitch / 2)
gaps = cq.Workplane("XY")
for i in range(TEETH_COUNT):
    x_pos = start_x + i * pitch
    gaps = gaps.union(gap_cutter.translate((x_pos, 0, 0)))

# Final rack geometry
rack = rack_base.cut(gaps)

# Add mounting holes on the sides
# Holes are drilled through the Z axis or from the side? 
# "отверстия 6,5 мм сбоку" usually means through the side faces or on the base.
# We'll place them on the bottom face (XY) for mounting to a surface.
rack = (
    rack.faces("<Z").workplane()
    .pushPoints([(-HOLE_DIST/2, 0), (HOLE_DIST/2, 0)])
    .hole(HOLE_D)
)

# Add some finishing touches
rack = rack.edges("|Z").fillet(0.5)

# Assembly
assy = cq.Assembly()
assy.add(rack, name="gear_rack", color=cq.Color(0.7, 0.7, 0.7))

result = assy
