Skip to content

Latest commit

 

History

History
202 lines (153 loc) · 6.53 KB

File metadata and controls

202 lines (153 loc) · 6.53 KB

Physical Units And Dimension Inference

SimpleCADAPI attaches physical meaning at Var declarations and infers the dimension of every derived scalar expression. This catches invalid formulas before they reach geometry, tolerance analysis, model export, replay, or FreeCAD translation.

Canonical CAD Units

Declaration values are preserved on each Var, but evaluation converts them to a single CAD coordinate system:

Dimension Canonical unit
Dimensionless 1
Length mm
Area mm^2
Volume mm^3
Angle deg

Degrees are canonical because existing SimpleCAD rotation and angular APIs use degrees. Trigonometric evaluation converts to radians internally and converts inverse-trigonometric results back to degrees.

import math
import simplecadapi as scad

width = scad.var("width", 1.0, unit="in")
angle = scad.var("angle", math.pi / 2, unit="rad")

assert width.default == 1.0
assert width.evaluate() == 25.4
assert angle.evaluate() == 90.0
assert math.isclose(scad.sin(angle).evaluate(), 1.0)

Bindings use the variable's declaration unit. width.evaluate({"width": 2.0}) therefore returns 50.8 millimeters for an inch-declared variable.

Declaring Units And Tolerances

width = scad.var(
    "width",
    1.0,
    unit="in",
    tolerance=(-0.1, 0.2),
    tolerance_unit="mm",
)
  • default is in unit.
  • tolerance is in tolerance_unit.
  • tolerance_unit defaults to unit when a tolerance is present.
  • Nominal and tolerance units may differ, but their dimensions must match.
  • A tolerance_unit requires both unit and tolerance.
  • Values must be finite and representable after canonical conversion.

width.default and width.tolerance preserve declaration-space values. width.canonical_default and width.canonical_tolerance expose values used by geometry and tolerance propagation.

Built-In Units

Dimension Symbols
Dimensionless 1, %
Length mm, cm, m, in, ft
Area mm^2, cm^2, m^2, in^2, ft^2
Volume mm^3, cm^3, m^3, in^3, ft^3
Angle deg, rad

Common singular/plural names are accepted by get_unit(), including millimeters, inches, feet, degrees, radians, square feet, and cubic inches. ml aliases cm^3.

Use constants such as MM, INCH, DEGREE, RADIAN, LENGTH, and ANGLE, or resolve strings:

assert scad.get_unit("inch") == scad.INCH
assert scad.convert_value(1.0, "in", "mm") == 25.4
assert math.isclose(scad.convert_value(180.0, "deg", "rad"), math.pi)

Incompatible conversion raises UnitValidationError.

Dimension Algebra

Dimension stores integer exponents for length and angle. Named dimensions are:

  • DIMENSIONLESS = Dimension()
  • LENGTH = Dimension(length=1)
  • AREA = Dimension(length=2)
  • VOLUME = Dimension(length=3)
  • ANGLE = Dimension(angle=1)

infer_dimension(expression) applies these rules:

Operation Rule
a + b, a - b dimensions must match
a * b add dimension exponents
a / b subtract dimension exponents
a ** n multiply exponents by constant integer n
sqrt(a) or a ** 0.5 every exponent must be even
unary -a, abs(a) preserve dimension
sin, cos, tan input must be Angle; result is Dimensionless
asin, acos, atan input must be Dimensionless; result is Angle
atan2(y, x) inputs must have the same dimension; result is Angle

Arbitrary and varying powers are permitted for dimensionless bases. A dimensioned base requires a constant integer exponent, except 0.5 is accepted when all base exponents are even.

width = scad.var("width", 30.0, unit="mm")
height = scad.var("height", 40.0, unit="mm")

area = width * height
diagonal = scad.sqrt(width**2 + height**2)

assert scad.infer_dimension(area) == scad.AREA
assert scad.infer_dimension(diagonal) == scad.LENGTH
assert diagonal.evaluate() == 50.0

Numeric Constants

Numeric literals are dimensionless coefficients in multiplication and division. For addition and subtraction, a literal adopts the other operand's dimension as a contextual offset:

length = scad.var("length", 10.0, unit="mm")
assert scad.infer_dimension(length * 2.0) == scad.LENGTH
assert scad.infer_dimension(length + 2.0) == scad.LENGTH

The literal is already expressed in the canonical result unit. length + 2.0 therefore means two millimeters, not two units of length.unit. Prefer explicit variables when declaration-unit intent must be retained.

Legacy Unitless Expressions

Variables without unit retain the previous behavior:

  • infer_dimension() returns None.
  • Trigonometric inputs and results use radians.
  • Existing arbitrary expression and tolerance behavior remains available.
  • A legacy variable cannot be mixed with a unit-declared variable in one expression because no safe physical meaning can be inferred.

Pure numeric constant expressions infer Dimensionless.

Custom Units

Custom linear-scale units use the same canonical system:

thou = scad.Unit("thou", scad.LENGTH, 0.0254)
width = scad.var("width", 1000.0, unit=thou)
assert width.evaluate() == 25.4

Built-in units serialize as symbols. Custom units serialize a definition:

{
  "symbol": "thou",
  "dimension": {"length": 1, "angle": 0},
  "scale_to_canonical": 0.0254
}

Units are scale-only. Offset units such as Celsius/Fahrenheit are not represented.

Validation Boundaries

Unit and dimension validation runs when:

  1. A Var, Dimension, or Unit is created.
  2. An expression is directly evaluated.
  3. An expression is registered or imported through ExpressionGraph.
  4. A tolerance is analyzed or a requirement is declared.
  5. Session/model JSON is imported, exported, replayed, or translated.

Malformed units, cyclic graphs, duplicate expression IDs, mixed legacy/typed variables, incompatible dimensions, invalid roots, and invalid trigonometric inputs are rejected before graph mutation or geometry replay.

Manufacturing Requirement Scope

Area, volume, inverse length, and other compound dimensions can be inferred and analyzed. Manufacturing requirements created by check_tolerance() or GraphSession.require_tolerance() currently accept final Length and Angle results only. This prevents an area or volume variation from being presented as a linear dimension requirement without explicit engineering semantics.

See Dimension Tolerance Chains for propagation, RSS assumptions, enforcement boundaries, and serialized requirement fields.