{
  "schemaVersion": 1,
  "slug": "crop-factor-calculator",
  "category": "photography",
  "kind": "implementation",
  "independentValidation": false,
  "implementationHash": "d7c80f7bb6d2111fb39d5daf7a62c969fdc4ea8707e3e8465d8366a11480f250",
  "provenance": "Generated from the calculation contract used by the published page. Publication is not external validation.",
  "sourceFiles": [
    "data/calculators/crop-factor-calculator.json",
    "src/engine.js"
  ],
  "runtimeSource": "/sources/engine.txt",
  "runtimeHash": "5c888d8898afbdee36267bb9977829e1e2ac568f6677c8ee87469c139864645c",
  "scope": "The compute function records implemented equations, constants, lookup tables and custom rules. Inputs record defaults and allowed values; outputs record precision and units. Defaults are examples, not recommendations. General background references are not evidence for this specific algorithm.",
  "publishedFormula": {
    "formula": "f_eq = f × c;  θ = 2 × atan(43.2666 ÷ (2 × c × f)) × 180 ÷ π",
    "vars": [
      [
        "c",
        "Crop factor"
      ],
      [
        "f",
        "Focal length (mm)"
      ],
      [
        "d",
        "Subject distance"
      ],
      [
        "θ",
        "Diagonal angle of view (°)"
      ]
    ],
    "note": "Diagonal sensor size = 43.2666 mm ÷ crop factor; diagonal angle of view and diagonal field of view follow from that diagonal. Horizontal width requires a sensor aspect ratio, which is not an input. Equivalent aperture is a depth-of-field comparison."
  },
  "externalEvidence": null,
  "contract": {
    "compute": "const cf = sensor; const diag = 43.2666/cf; const equivalent = focalLength*cf; const eqAperture = aperture*cf; const aov = 2*Math.atan(diag/(2*focalLength))*180/Math.PI; const fov = distance*2*Math.tan(aov/2*Math.PI/180); return { equivalentFocal: equivalent, equivalentAperture: eqAperture, cropFactor: cf, angleOfView: aov, fieldOfView: fov, sensorDiagonalMm: diag };",
    "inputs": [
      {
        "name": "sensor",
        "type": "select",
        "default": 1.5,
        "options": [
          {
            "value": 1
          },
          {
            "value": 0.79
          },
          {
            "value": 1.3
          },
          {
            "value": 1.5
          },
          {
            "value": 1.6
          },
          {
            "value": 2
          },
          {
            "value": 2.7
          },
          {
            "value": 4.55
          }
        ]
      },
      {
        "name": "focalLength",
        "type": "number",
        "default": 50,
        "min": 1,
        "max": 2000,
        "step": 1,
        "slider": true
      },
      {
        "name": "aperture",
        "type": "number",
        "default": 1.8,
        "min": 0.7,
        "max": 64,
        "step": 0.1,
        "slider": true
      },
      {
        "name": "distance",
        "type": "number",
        "default": 5,
        "min": 0.01,
        "max": 100000,
        "step": 0.1
      }
    ],
    "outputs": [
      {
        "name": "equivalentFocal",
        "precision": 1,
        "unit": "mm"
      },
      {
        "name": "equivalentAperture",
        "precision": 2,
        "unit": "f/"
      },
      {
        "name": "cropFactor",
        "precision": 2,
        "unit": ""
      },
      {
        "name": "angleOfView",
        "precision": 2,
        "unit": "degrees"
      },
      {
        "name": "fieldOfView",
        "precision": 2,
        "unit": "m"
      },
      {
        "name": "sensorDiagonalMm",
        "precision": 2,
        "unit": "mm"
      }
    ],
    "interpret": null
  }
}
