// Car Wheel
// A sports car wheel with a circular lug pattern and spokes.

// Set units
@settings(defaultLengthUnit = in, kclVersion = 1.0)

// Import parameters
import lugCount, lugSpacing, offset, backSpacing, wheelWidth, wheelDiameter, spokeCount, spokeGap, spokeAngle, spokeThickness from "parameters.kcl"

// Create the wheel center
lugBase = startSketchOn(XZ)
  |> circle(center = [0, 0], radius = (lugSpacing + 1.5) / 2)
  |> subtract2d(tool = circle(center = [0, 0], radius = (lugSpacing - 1.5) / 2))
  |> extrude(length = wheelWidth / 20)

// Extend the wheel center and bore holes to accomidate the lug heads
lugExtrusion = startSketchOn(lugBase, face = END)
  |> circle(center = [0, 0], radius = (lugSpacing + 1.5) / 2)
  |> subtract2d(tool = circle(center = [0, 0], radius = (lugSpacing - 1.5) / 2))
  |> extrude(length = wheelWidth / 10)

// Create the circular pattern for the lugs
lugClearance = startSketchOn(lugExtrusion, face = END)
  |> circle(center = [lugSpacing / 2, 0], radius = 1.2 / 2)
  |> patternCircular2d(
       arcDegrees = 360,
       center = [0, 0],
       instances = lugCount,
       rotateDuplicates = true,
     )
  |> extrude(length = -wheelWidth / 10)

// Create the circular pattern for the lug holes
lugHoles = startSketchOn(lugBase, face = END)
  |> circle(center = [lugSpacing / 2, 0], radius = 16mm / 2)
  |> patternCircular2d(
       arcDegrees = 360,
       center = [0, 0],
       instances = lugCount,
       rotateDuplicates = true,
     )
  |> extrude(length = -wheelWidth / 20)
  |> appearance(color = "#ffffff", metalness = 0, roughness = 0)

// Add detail to the wheel center by revolving curved edge profiles
wheelCenterInner = startSketchOn(XY)
  |> startProfile(at = [(lugSpacing - 1.5) / 2, 0])
  |> yLine(length = -wheelWidth / 10 - (wheelWidth / 20))
  |> bezierCurve(control1 = [-0.3, 0], control2 = [0, 0.3], end = [-0.4, 0.3])
  |> yLine(endAbsolute = 0)
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
  |> close()
  |> revolve(axis = Y)
  |> appearance(color = "#ffffff", metalness = 0, roughness = 0)

wheelCenterOuter = startSketchOn(XY)
  |> startProfile(at = [(lugSpacing + 1.5) / 2, 0])
  |> yLine(length = -wheelWidth / 10 - (wheelWidth / 20))
  |> bezierCurve(control1 = [0.3, 0], control2 = [0.2, -0.3], end = [0.4, -0.1])
  |> yLine(endAbsolute = -wheelWidth / 20)
  |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
  |> close()
  |> revolve(axis = Y)
  |> appearance(color = "#ffffff", metalness = 0, roughness = 0)

// Write a function that defines the spoke geometry, patterns and extrudes it
fn spoke(spokeGap, spokeAngle, spokeThickness) {
  // Seperating the spoke base planes
  plane001 = {
    origin = [0.0, 0.0, spokeGap / 2],
    xAxis = [1.0, 0.0, spokeAngle],
    yAxis = [0.0, 1.0, 0.0],
    zAxis = [0.0, 0.0, 1.0]
  }

  // Spoke cross sections
  spokeProfile = startSketchOn(plane001)
    |> startProfile(at = [(lugSpacing + 2) / 2, -0.7])
    |> bezierCurve(
         control1 = [
           (wheelDiameter - lugSpacing - 2.9) / 3.5,
           offset / 7
         ],
         control2 = [
           (wheelDiameter - lugSpacing - 2.9) / 4,
           offset / 1.5
         ],
         end = [
           (wheelDiameter - lugSpacing - 2.9) / 2,
           offset
         ],
       )
    |> yLine(length = -wheelWidth / 15)
    |> bezierCurve(
         control1 = [
           -(wheelDiameter - lugSpacing - 2.9) / 5,
           -offset / 7
         ],
         control2 = [
           -(wheelDiameter - lugSpacing - 2.9) / 5,
           -offset / 1.5
         ],
         end = [
           -(wheelDiameter - lugSpacing - 2.9) / 2,
           -offset
         ],
       )
    |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
    |> close()

  // Circular pattern spokes
  spokePattern = extrude(spokeProfile, length = spokeThickness)
    |> patternCircular3d(
         axis = [0, 1, 0],
         center = [0, -2000, 0],
         instances = spokeCount,
         arcDegrees = 360,
         rotateDuplicates = true,
       )
    |> appearance(color = "#ffffff", metalness = 0, roughness = 0)
  return spokePattern
}

spoke(spokeGap = spokeGap, spokeAngle = spokeAngle, spokeThickness = spokeThickness)
spoke(spokeGap = -spokeGap, spokeAngle = -spokeAngle, spokeThickness = -spokeThickness)

// Define and revolve wheel exterior
startSketchOn(XY)
  |> startProfile(at = [
       wheelDiameter / 2,
       -wheelWidth + backSpacing + offset
     ])
  |> yLine(length = wheelWidth * 0.25)
  |> line(end = [-wheelWidth * 0.02, wheelWidth * 0.02])
  |> yLine(length = wheelWidth * 0.25)
  |> line(end = [wheelWidth * 0.02, wheelWidth * 0.02])
  |> yLine(endAbsolute = backSpacing + offset)
  |> line(end = [wheelWidth * 0.05, wheelWidth * .01])
  |> yLine(length = wheelWidth * 0.05)
  |> xLine(length = -wheelWidth * 0.03)
  |> yLine(length = -wheelWidth * 0.02)
  |> line(end = [-wheelWidth * 0.05, -wheelWidth * 0.01])
  |> yLine(length = -backSpacing * 0.7)
  |> line(end = [
       -wheelDiameter * 0.01,
       -wheelWidth * 0.02
     ])
  |> yLine(endAbsolute = offset - 0.2)
  |> line(end = [
       -wheelDiameter * 0.03,
       -wheelWidth * 0.02
     ])
  |> yLine(length = -wheelWidth * 0.02)
  |> line(end = [
       wheelDiameter * 0.03,
       -wheelWidth * 0.1
     ])
  |> yLine(length = -wheelWidth * 0.05)
  |> line(end = [wheelWidth * 0.02, -wheelWidth * 0.02])
  |> yLine(endAbsolute = -wheelWidth + backSpacing + offset - 0.28)
  |> line(end = [wheelWidth * 0.05, -wheelWidth * 0.01])
  |> yLine(length = -wheelWidth * 0.02)
  |> xLine(length = wheelWidth * 0.03)
  |> yLine(length = wheelWidth * 0.05)
  |> close()
  |> revolve(axis = Y)
  |> appearance(color = "#ffffff", metalness = 0, roughness = 0)
