python-cad-tools 0.1.17__tar.gz → 0.1.19__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/.github/workflows/ci.yml +19 -28
  2. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/CHANGELOG.md +42 -0
  3. {python_cad_tools-0.1.17/src/python_cad_tools.egg-info → python_cad_tools-0.1.19}/PKG-INFO +1 -1
  4. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/docs/public-api.md +9 -7
  5. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/docs/spikes/curved-geometry-ifc-bounds.md +18 -1
  6. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/docs/toolchain.md +3 -1
  7. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/artifacts.py +19 -8
  8. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/build.py +10 -2
  9. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/context.py +2 -0
  10. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/drawings/__init__.py +22 -0
  11. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/elements.py +12 -0
  12. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/ifc.py +3 -3
  13. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/geometry.py +90 -15
  14. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/manifests.py +38 -3
  15. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/units.py +13 -0
  16. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/validation.py +17 -4
  17. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19/src/python_cad_tools.egg-info}/PKG-INFO +1 -1
  18. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/scm_file_list.json +2 -0
  19. python_cad_tools-0.1.19/src/python_cad_tools.egg-info/scm_version.json +8 -0
  20. python_cad_tools-0.1.17/src/python_cad_tools.egg-info/scm_version.json +0 -8
  21. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/.gitattributes +0 -0
  22. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/.githooks/pre-push +0 -0
  23. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/.github/workflows/downstream-compatibility.yml +0 -0
  24. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/.github/workflows/release-candidate.yml +0 -0
  25. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/.github/workflows/release.yml +0 -0
  26. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/.gitignore +0 -0
  27. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/.opencode/commands/autocommit.md +0 -0
  28. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/.opencode/tools/specrepo-autocommit.js +0 -0
  29. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/.opencode/tools/specrepo-autocommit.py +0 -0
  30. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/AGENTS.md +0 -0
  31. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/CLAUDE.md +0 -0
  32. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/LICENSE +0 -0
  33. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/MANIFEST.in +0 -0
  34. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/README.md +0 -0
  35. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/docs/build-semantics.md +0 -0
  36. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/docs/drawing-extensions.md +0 -0
  37. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/docs/manifests.md +0 -0
  38. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/docs/neutral-model.md +0 -0
  39. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/docs/project-configuration.md +0 -0
  40. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/docs/spikes/format-feasibility.md +0 -0
  41. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/docs/two-tier-contract.md +0 -0
  42. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/docs/viewer-delivery.md +0 -0
  43. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/pyproject.toml +0 -0
  44. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/setup.cfg +0 -0
  45. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/__init__.py +0 -0
  46. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/__main__.py +0 -0
  47. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_locking.py +0 -0
  48. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_project_loader.py +0 -0
  49. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_project_state.py +0 -0
  50. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_scaffold.py +0 -0
  51. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_transaction.py +0 -0
  52. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/app.webmanifest +0 -0
  53. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/asset-manifest.json +0 -0
  54. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/animationGroup-CMgMiFPo.js +0 -0
  55. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/bakedVertexAnimation-BlpwZEna.js +0 -0
  56. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/basisTextureLoader-pxgVvwE7.js +0 -0
  57. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/brdfTextureTools-CL1Nnrm1.js +0 -0
  58. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/bumpFragment-BNBjNOnF.js +0 -0
  59. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/bumpVertex-BTawYPw8.js +0 -0
  60. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/bumpVertexDeclaration-B_fffQFY.js +0 -0
  61. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/clipPlaneFragment-D1ZAafqO.js +0 -0
  62. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/clipPlaneVertex-BC_wnvpq.js +0 -0
  63. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/cubemapToSphericalPolynomial-DeA9LJ87.js +0 -0
  64. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/dds-C5zm4fz8.js +0 -0
  65. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/dds.pure-B_7lJeYI.js +0 -0
  66. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/ddsTextureLoader-DsS5rL5j.js +0 -0
  67. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/default.fragment-BUHDudIn.js +0 -0
  68. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/default.vertex-B80Wq2Ab.js +0 -0
  69. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/defaultUboDeclaration-DuGcl3VN.js +0 -0
  70. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/dumpTools-1F1Rx0a0.js +0 -0
  71. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/envTextureLoader-DqI1ceC5.js +0 -0
  72. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/exrTextureLoader-DmNwF2B5.js +0 -0
  73. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphApplyForceBlock-DmvfeucL.js +0 -0
  74. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphApplyImpulseBlock-ChgIpPqh.js +0 -0
  75. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphArrayIndexBlock-_JwXSrlj.js +0 -0
  76. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphBezierCurveEasingBlock-B-T0qVRw.js +0 -0
  77. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphBinaryOperationBlock-TpZm5BfV.js +0 -0
  78. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphBranchBlock-CNwAs8cP.js +0 -0
  79. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphCachedOperationBlock-DaEYpjja.js +0 -0
  80. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphCancelDelayBlock-Dc4RKYSf.js +0 -0
  81. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphCodeExecutionBlock-DCxeE8wr.js +0 -0
  82. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphConditionalDataBlock-TckZ2SGl.js +0 -0
  83. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphConsoleLogBlock-B5e69wX5.js +0 -0
  84. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphConstantBlock-3ktOI1lC.js +0 -0
  85. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphContextBlock-XTBtETD_.js +0 -0
  86. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphCounterBlock-Pb64y9OD.js +0 -0
  87. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphDataSwitchBlock-DsG4QDCF.js +0 -0
  88. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphDebounceBlock-B_XjPDoZ.js +0 -0
  89. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphDebugBlock-CD6lTvpS.js +0 -0
  90. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphDoNBlock-0NvER8W0.js +0 -0
  91. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphEasingBlock-B6hapywt.js +0 -0
  92. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphFlipFlopBlock-D1uyBOpq.js +0 -0
  93. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphForLoopBlock-BYD81Gof.js +0 -0
  94. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphFunctionReferenceBlock-zABkEq-X.js +0 -0
  95. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGLTFDataProvider-B0ofoVrD.js +0 -0
  96. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetAngularVelocityBlock-DPTUNnTb.js +0 -0
  97. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetAssetBlock-B8_99mSz.js +0 -0
  98. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetLinearVelocityBlock-DFYXgPrA.js +0 -0
  99. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetPhysicsMassPropertiesBlock-DA6AqPR7.js +0 -0
  100. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetPropertyBlock-Bp4o9QmW.js +0 -0
  101. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetSoundVolumeBlock-BAmdegmU.js +0 -0
  102. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphGetVariableBlock-Cd8Y6leR.js +0 -0
  103. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphIndexOfBlock-CGYxKZZY.js +0 -0
  104. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphInterpolationBlock-CwjeWPr7.js +0 -0
  105. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphIsKeyPressedBlock-rNAEqrST.js +0 -0
  106. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphIsSoundPlayingBlock-BTztAQ_0.js +0 -0
  107. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphJsonPointerParserBlock-DoLWKXUb.js +0 -0
  108. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyDownEventBlock-DPIi37WK.js +0 -0
  109. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyUpEventBlock-ZV1Tim4d.js +0 -0
  110. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyboardEventBlock-ClUSFYDa.js +0 -0
  111. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphMathBlocks-BEiYY5fC.js +0 -0
  112. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphMathCombineExtractBlocks-CVfFjT4m.js +0 -0
  113. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphMatrixMathBlocks-B6l0dCDc.js +0 -0
  114. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphMeshPickEventBlock-kdpuo1mU.js +0 -0
  115. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphMultiGateBlock-n99NMOON.js +0 -0
  116. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPauseAnimationBlock-DXKPP4nK.js +0 -0
  117. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPauseSoundBlock-e2k4W8Bc.js +0 -0
  118. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPhysicsCollisionEventBlock-ClgKwXfJ.js +0 -0
  119. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPlayAnimationBlock-BZj6MNgX.js +0 -0
  120. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPlaySoundBlock-BnzlrpjK.js +0 -0
  121. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerDownEventBlock-CQiX1RZi.js +0 -0
  122. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerMoveEventBlock-B_JzBfd9.js +0 -0
  123. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerOutEventBlock-B-xKCRP6.js +0 -0
  124. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerOverEventBlock-DPC5GKft.js +0 -0
  125. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerUpEventBlock-hCR14WZY.js +0 -0
  126. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphReceiveCustomEventBlock-EOc5SmbK.js +0 -0
  127. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSceneReadyEventBlock-BAOJ-S5R.js +0 -0
  128. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSceneTickEventBlock-BJla1nDw.js +0 -0
  129. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSendCustomEventBlock-CbJzCBSw.js +0 -0
  130. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSequenceBlock-C0E5Vhwk.js +0 -0
  131. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetAngularVelocityBlock-Crx1sltA.js +0 -0
  132. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetDelayBlock-t-D4JM8I.js +0 -0
  133. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetLinearVelocityBlock-DKNa-lhN.js +0 -0
  134. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetPhysicsMotionTypeBlock-BIeMWJwi.js +0 -0
  135. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetPropertyBlock-CFERwfo5.js +0 -0
  136. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetSoundVolumeBlock-B8fGBso9.js +0 -0
  137. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSetVariableBlock-D3NUXLsU.js +0 -0
  138. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSoundEndedEventBlock-BsojQIIQ.js +0 -0
  139. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphStopAnimationBlock-Bhvi4mzM.js +0 -0
  140. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphStopSoundBlock-BL-vDlPP.js +0 -0
  141. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphSwitchBlock-q5uox2Ll.js +0 -0
  142. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphThrottleBlock-ZvIobaF-.js +0 -0
  143. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphTransformCoordinatesSystemBlock-DC7IZTrj.js +0 -0
  144. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphTypeToTypeBlocks-DsmLuQmd.js +0 -0
  145. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphUnaryOperationBlock-CeFOvM8N.js +0 -0
  146. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphVectorMathBlocks-O_o0PB3R.js +0 -0
  147. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphWaitAllBlock-CS8S_sto.js +0 -0
  148. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/flowGraphWhileLoopBlock-BogzY-TI.js +0 -0
  149. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/fogFragment-5iY5mDF9.js +0 -0
  150. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting-CzELCfrg.js +0 -0
  151. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting-Dm4qQcCl.js +0 -0
  152. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.fragment-Dl5Knagi.js +0 -0
  153. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.fragment-gV6NfBr2.js +0 -0
  154. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.vertex-BU7N8GWm.js +0 -0
  155. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.vertex-BYh0LKwp.js +0 -0
  156. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.fragment-DGCqlu5B.js +0 -0
  157. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.fragment-DPRpU6I6.js +0 -0
  158. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.vertex-D6831_Db.js +0 -0
  159. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.vertex-DVVqYQkj.js +0 -0
  160. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/geometry.fragment-CJ5P29rW.js +0 -0
  161. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/geometry.fragment-eMPAGW-C.js +0 -0
  162. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/geometry.vertex-Cfmd-eH1.js +0 -0
  163. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/geometry.vertex-D8aj2PHd.js +0 -0
  164. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/glowBlurPostProcess.fragment-BNUj6Ok4.js +0 -0
  165. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/glowMapGeneration.fragment-BMfCbDSO.js +0 -0
  166. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/glowMapGeneration.vertex-HFoIGtvW.js +0 -0
  167. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/glowMapMerge.fragment-DcbXX8O5.js +0 -0
  168. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/glowMapMerge.vertex-C6kfp5Df.js +0 -0
  169. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/harmonicsFunctions-B_Rux4W4.js +0 -0
  170. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/hdrTextureLoader-BGQvgh0h.js +0 -0
  171. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/helperFunctions-DfEEUVrK.js +0 -0
  172. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/iesTextureLoader-DRIv8q-c.js +0 -0
  173. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/index-Bi_hQlRi.css +0 -0
  174. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/index-QUv88KPb.js +0 -0
  175. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlur.fragment-AIxPvzg7.js +0 -0
  176. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlur.fragment-B-fzpNXl.js +0 -0
  177. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlur.vertex-BeCpz_iB.js +0 -0
  178. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlur.vertex-LF_ZsFNn.js +0 -0
  179. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlurVaryingDeclaration-0MaBFn29.js +0 -0
  180. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/kernelBlurVaryingDeclaration-CKf1P4fb.js +0 -0
  181. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/ktxTextureLoader-tKPsUacI.js +0 -0
  182. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/lightFragment-k2nRX45x.js +0 -0
  183. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/logDepthDeclaration-BGXXcOUJ.js +0 -0
  184. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/logDepthVertex-BC72KyzN.js +0 -0
  185. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/mainUVVaryingDeclaration-BCMZuxRE.js +0 -0
  186. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/mesh.vertexData.functions-ayNlGC5K.js +0 -0
  187. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/meshUboDeclaration-Cxk75_zo.js +0 -0
  188. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/oitFragment-BtwWIihL.js +0 -0
  189. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbr.fragment-8rnUKL54.js +0 -0
  190. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbr.fragment-C6yWZfQI.js +0 -0
  191. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbr.vertex-DGh-kC4B.js +0 -0
  192. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbr.vertex-DbnVIs8Y.js +0 -0
  193. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrMaterial.pure-CFHhabYh.js +0 -0
  194. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrMaterialLoadingAdapter-BQGAj-f6.js +0 -0
  195. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrTransmissionLayerData-BMK7l2Ba.js +0 -0
  196. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrTransmissionLayerData-DNsGu5u0.js +0 -0
  197. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrUboDeclaration-Cd1JAAAL.js +0 -0
  198. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/openpbrUboDeclaration-rBzbf9n3.js +0 -0
  199. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/packingFunctions-Dji1Rr-b.js +0 -0
  200. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/packingFunctions-_goA4OEm.js +0 -0
  201. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pass.fragment-CgGToehX.js +0 -0
  202. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/passCube.fragment-CqqQ20XF.js +0 -0
  203. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/passCube.fragment-D93dlgjG.js +0 -0
  204. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbr.fragment-YSvcDJjz.js +0 -0
  205. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbr.vertex-BOhSAeHX.js +0 -0
  206. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrBRDFFunctions-DTEwurLZ.js +0 -0
  207. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrDebug-B4IzJZHZ.js +0 -0
  208. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrIBLFunctions-gJ0KErMb.js +0 -0
  209. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrMaterial.pure-BRIxFz02.js +0 -0
  210. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrMaterialLoadingAdapter--NRrZRBU.js +0 -0
  211. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/pbrUboDeclaration-6dxbcrtA.js +0 -0
  212. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/postprocess.vertex-ZxthID8t.js +0 -0
  213. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/procedural.vertex-BSVnGss-.js +0 -0
  214. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/procedural.vertex-DzIg_d-k.js +0 -0
  215. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/reflectionFunction-CgKY-0t6.js +0 -0
  216. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/rgbdDecode.fragment-CAfeJDpQ.js +0 -0
  217. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/rgbdEncode.fragment-D7xEO0B-.js +0 -0
  218. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/rgbdEncode.fragment-DIzz0LC4.js +0 -0
  219. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/sceneUboDeclaration-kGrRDglr.js +0 -0
  220. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/textureProcessor.fragment-CgQTw0M7.js +0 -0
  221. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/textureProcessor.fragment-DnEEx4Gs.js +0 -0
  222. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/tgaTextureLoader-CwaQqeYn.js +0 -0
  223. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/assets/vertexColorMixing-C2cK_vck.js +0 -0
  224. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/favicon.svg +0 -0
  225. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/index.html +0 -0
  226. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/_viewer_static/sw.js +0 -0
  227. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/build-info.json +0 -0
  228. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/cli.py +0 -0
  229. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/determinism.py +0 -0
  230. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/drawings/_catalog.py +0 -0
  231. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/drawings/_validation.py +0 -0
  232. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exceptions.py +0 -0
  233. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/__init__.py +0 -0
  234. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/base.py +0 -0
  235. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/__init__.py +0 -0
  236. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/annotations.py +0 -0
  237. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/dxf.py +0 -0
  238. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/model.py +0 -0
  239. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/pdf.py +0 -0
  240. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/primitives.py +0 -0
  241. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/projection.py +0 -0
  242. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/drawings/svg.py +0 -0
  243. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/glb.py +0 -0
  244. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/quantities.py +0 -0
  245. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/exporters/step.py +0 -0
  246. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/project_config.py +0 -0
  247. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/py.typed +0 -0
  248. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/recipes.py +0 -0
  249. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/runtime_sync.py +0 -0
  250. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/build-manifest-1.json +0 -0
  251. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/design-manifest-1.json +0 -0
  252. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/download-manifest-2.json +0 -0
  253. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/drawing-annotations-1.json +0 -0
  254. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/glb-manifest-1.json +0 -0
  255. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/ifc-validation-1.json +0 -0
  256. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/quantities-1.json +0 -0
  257. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/run-metadata-1.json +0 -0
  258. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/site-metadata-1.json +0 -0
  259. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/schemas/step-validation-1.json +0 -0
  260. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/site.py +0 -0
  261. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/.gitignore +0 -0
  262. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/README.md +0 -0
  263. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/config.py +0 -0
  264. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/drawing_annotations.py +0 -0
  265. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/generated/.gitkeep +0 -0
  266. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/model.py +0 -0
  267. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools/templates/project/pyproject.toml +0 -0
  268. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/SOURCES.txt +0 -0
  269. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/dependency_links.txt +0 -0
  270. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/entry_points.txt +0 -0
  271. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/requires.txt +0 -0
  272. {python_cad_tools-0.1.17 → python_cad_tools-0.1.19}/src/python_cad_tools.egg-info/top_level.txt +0 -0
@@ -17,6 +17,12 @@
17
17
  # creates the tag and triggers this run. Keeping publish logic in one
18
18
  # gated place (instead of duplicating it in release.yml) avoids two
19
19
  # workflows racing to publish the same version.
20
+ #
21
+ # Test tiers (workspace test-cost-reduction, 2026-10-12): pushes and pull
22
+ # requests run the checks a code change can break on Linux, plus one macOS
23
+ # platform job. Version tags and manual dispatch (the release path, before
24
+ # PyPI) also run Windows, the per-extra toolchain matrix on macOS and Linux,
25
+ # and the platform locks. macOS minutes bill 10x on this private repository.
20
26
  name: CI
21
27
 
22
28
  on:
@@ -227,15 +233,15 @@ jobs:
227
233
  done
228
234
  echo "All tree shape checks passed."
229
235
 
230
- # Confirms init/build works on Linux, macOS, and Windows. Windows
231
- # skips ruff/mypy since static checks aren't part of the
232
- # cross-platform contract, just the CLI behavior.
236
+ # Confirms init/build works on Linux, macOS, and Windows (Windows only
237
+ # on the release tier). Windows skips ruff/mypy since static checks
238
+ # aren't part of the cross-platform contract, just the CLI behavior.
233
239
  supported-platforms:
234
240
  name: Supported platforms (${{ matrix.os }})
235
241
  strategy:
236
242
  fail-fast: false
237
243
  matrix:
238
- os: [ubuntu-latest, macos-latest, windows-latest]
244
+ os: ${{ fromJSON((startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch') && '["ubuntu-latest","macos-latest","windows-latest"]' || '["ubuntu-latest","macos-latest"]') }}
239
245
  runs-on: ${{ matrix.os }}
240
246
  steps:
241
247
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
@@ -263,9 +269,10 @@ jobs:
263
269
 
264
270
  # Generates a per-OS `pip freeze` lockfile as a downloadable
265
271
  # artifact for reference. Informational only — not enforced or
266
- # committed anywhere automatically.
272
+ # committed anywhere automatically. Release tier only.
267
273
  platform-locks:
268
274
  name: Platform lock generation (${{ matrix.os }})
275
+ if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch'
269
276
  strategy:
270
277
  fail-fast: false
271
278
  matrix:
@@ -297,40 +304,27 @@ jobs:
297
304
  path: ${{ matrix.lock }}
298
305
 
299
306
  # Confirms every optional dependency group (cad, bim, mesh, ...)
300
- # installs cleanly and imports across OS/Python combinations. PRs
301
- # only run a fast subset (core+all on ubuntu/py3.13) via the gate
302
- # step below; main and tag pushes run the full matrix.
307
+ # installs cleanly and imports across OS/Python combinations. Pushes
308
+ # and PRs run core and all on Linux for both Pythons; the release tier
309
+ # runs every group on Linux and macOS. The matrix itself is narrowed,
310
+ # so no runner starts for a cell that would be skipped.
303
311
  toolchain-matrix:
304
312
  name: Toolchain matrix (${{ matrix.os }}, py${{ matrix.python }}, ${{ matrix.group }})
305
313
  strategy:
306
314
  fail-fast: false
307
315
  matrix:
308
- os: [ubuntu-latest, macos-latest]
316
+ os: ${{ fromJSON((startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch') && '["ubuntu-latest","macos-latest"]' || '["ubuntu-latest"]') }}
309
317
  python: ["3.12", "3.13"]
310
- group: [core, cad, bim, mesh, drawings, engineering, visualization, all]
318
+ group: ${{ fromJSON((startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch') && '["core","cad","bim","mesh","drawings","engineering","visualization","all"]' || '["core","all"]') }}
311
319
  runs-on: ${{ matrix.os }}
312
320
  steps:
313
321
  - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
314
- # Full matrix on main/tags/release-candidates; a fast core+all subset on pull requests.
315
- - name: Determine whether this matrix cell runs
316
- id: gate
317
- run: |
318
- if [ "${{ github.event_name }}" = "pull_request" ] && \
319
- ! { [ "${{ matrix.os }}" = "ubuntu-latest" ] && [ "${{ matrix.python }}" = "3.13" ] && \
320
- { [ "${{ matrix.group }}" = "core" ] || [ "${{ matrix.group }}" = "all" ]; }; }; then
321
- echo "run=false" >> "$GITHUB_OUTPUT"
322
- else
323
- echo "run=true" >> "$GITHUB_OUTPUT"
324
- fi
325
322
  - uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
326
- if: steps.gate.outputs.run == 'true'
327
323
  with:
328
324
  python-version: ${{ matrix.python }}
329
325
  cache: pip
330
326
  - run: python -m pip install --upgrade pip
331
- if: steps.gate.outputs.run == 'true'
332
327
  - name: Install capability group
333
- if: steps.gate.outputs.run == 'true'
334
328
  run: |
335
329
  if [ "${{ matrix.group }}" = "core" ]; then
336
330
  pip install -e .
@@ -338,9 +332,7 @@ jobs:
338
332
  pip install -e ".[${{ matrix.group }}]"
339
333
  fi
340
334
  - run: pip check
341
- if: steps.gate.outputs.run == 'true'
342
335
  - name: Import declared libraries for this group
343
- if: steps.gate.outputs.run == 'true'
344
336
  run: |
345
337
  python - <<'PY'
346
338
  import importlib
@@ -384,7 +376,7 @@ jobs:
384
376
  print(json.dumps(report, indent=2, sort_keys=True))
385
377
  PY
386
378
  - name: Tier-2 interop smoke and no-GUI assertion
387
- if: steps.gate.outputs.run == 'true' && matrix.group == 'all'
379
+ if: matrix.group == 'all'
388
380
  run: |
389
381
  python - <<'PY'
390
382
  import sys
@@ -413,7 +405,6 @@ jobs:
413
405
  print("Tier-2 interop smoke and no-GUI assertion passed.")
414
406
  PY
415
407
  - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
416
- if: steps.gate.outputs.run == 'true'
417
408
  with:
418
409
  name: toolchain-compatibility-${{ matrix.os }}-py${{ matrix.python }}-${{ matrix.group }}
419
410
  path: toolchain-compatibility.json
@@ -7,6 +7,48 @@ stable release is published.
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.19] - 2026-10-19
11
+
12
+ ### Changed
13
+
14
+ - Every public function and class in the authoring modules (`artifacts`,
15
+ `build`, `context`, `drawings`, `elements`, `geometry`, `units`,
16
+ `validation`) has a one-line docstring stating its units and, for
17
+ geometry, its placement:
18
+ - `box` puts its minimum corner at the origin;
19
+ - `prism_between` starts at a bottom corner, with its width to the left
20
+ of the run;
21
+ - `Placement` is recorded only and never moves geometry.
22
+
23
+ Tools that list the public API with signatures and first docstring
24
+ lines now describe each helper. Behavior is unchanged.
25
+ - Routine CI runs a smaller platform and extras matrix. Version tags and
26
+ manual dispatch still run the full release matrix.
27
+
28
+ ## [0.1.18] - 2026-10-08
29
+
30
+ ### Fixed
31
+
32
+ - Curved B-rep solids (spheres, `cylinder_between` cylinders and other curved
33
+ shapes) no longer fail `build` and `verify` with `artifact_integrity:
34
+ IFC/design bounds mismatch`. The design manifest records each element's
35
+ `body_bounds_mm` (the bounds of the body IFC actually writes: the mesh of a
36
+ tessellated solid, the exact shape for recipes), and the IFC check compares
37
+ against it at the same `1e-6` tolerance. Manifests without the field fall
38
+ back to `bounds_mm`. `body_bounds_mm` describes the export, not the design,
39
+ so it is left out of `semantic_hash`: design hashes are unchanged, and
40
+ `validate` does not tessellate.
41
+ - `validate` reports a build123d `Part` (or compound) that holds one solid as
42
+ `solid-wrapped` with the fix (`.solid()`), instead of a bare
43
+ `solid-invalid`.
44
+
45
+ ### Changed
46
+
47
+ - A build tessellates each element once and shares the mesh between the
48
+ design manifest, IFC and GLB (`geometry.shared_tessellation`), instead of
49
+ IFC and GLB each meshing it. `benge-property-cad`'s full build went from
50
+ 106 s to 67 s on the owner's Mac.
51
+
10
52
  ## [0.1.16] - 2026-09-22
11
53
 
12
54
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-cad-tools
3
- Version: 0.1.17
3
+ Version: 0.1.19
4
4
  Summary: Typed, headless Python tooling for CAD/BIM models and artifacts
5
5
  Author: Brandon Benge
6
6
  License: AGPL-3.0-only
@@ -16,13 +16,15 @@ of optional runtime imports.
16
16
  `cubic_yards`, `metres`, and `square_metres`.
17
17
  - `python_cad_tools.geometry`: `box`, `reference_line`, `cylinder_between`,
18
18
  `prism_between`, `sloped_pool`, `bounds`, `combined_bounds`, `tessellate`,
19
- `is_valid_solid`, and `diagonal`. **Curved geometry that must pass the
20
- build pipeline's `artifact_integrity` IFC/design-bounds check should not
21
- use `cylinder_between`** -- its tessellated B-rep output cannot exactly
22
- match analytic design-side bounds. Use `python_cad_tools.recipes`'
23
- `CircleProfile` + `ExtrudedProfile` instead; see
24
- [`cylinder_between`'s docstring](../src/python_cad_tools/geometry.py) and
25
- `docs/spikes/curved-geometry-ifc-bounds.md` for the confirmed mechanism.
19
+ `is_valid_solid`, and `diagonal`. Curved B-rep solids (`cylinder_between`,
20
+ build123d spheres and other curved shapes) build and verify: IFC writes
21
+ them as triangle meshes, and the IFC bounds check compares that mesh with
22
+ the same tessellation recorded in the design manifest as `body_bounds_mm`
23
+ (0.1.18). Use `python_cad_tools.recipes`' `CircleProfile` +
24
+ `ExtrudedProfile` where an analytic IFC body is wanted instead of a mesh.
25
+ Pass a `Solid`: build123d algebra-mode shapes such as `Sphere(...)` are a
26
+ `Part` wrapping one solid, which `validate` reports as `solid-wrapped`
27
+ (use `.solid()`).
26
28
  - `python_cad_tools.drawings`: `Point2`, `Direction`, `DrawingStyleToken`,
27
29
  `DrawingSheet`, `Line`, `Polyline`, `Text`, `Dimension`, `SectionCallout`,
28
30
  `ElevationMarker`, `TableRow`, `Table`, `SheetAnnotations`, and
@@ -1,4 +1,21 @@
1
- # Curved geometry vs. the IFC/design bounds integrity check (mechanism confirmed empirically)
1
+ # Curved geometry vs. the IFC/design bounds integrity check
2
+
3
+ **Resolved in 0.1.18 (2026-10-08).** The mechanism is confirmed in source:
4
+ elements without a recipe are written to IFC as an `IfcTriangulatedFaceSet`
5
+ from `tessellate(geometry, 0.5, 0.25)`, the IFC report's bounds are read back
6
+ from those mesh coordinates, and the manifest recorded only the exact B-rep
7
+ bounds; `_reconcile_formats` compared the two at `1e-6`. The fix is candidate
8
+ direction 1 below ("compare like with like"): the design manifest now records
9
+ `body_bounds_mm`, the bounds of the same tessellation
10
+ (`geometry.IFC_TESSELLATION`, shared with the exporter), and the IFC check
11
+ compares against it, still exactly. A live hosted run on 2026-10-08 ("change
12
+ the cube to a sphere", `Sphere(152.4).solid()`) failed with x/y short by
13
+ 0.58 mm before the fix; `tests/integration/test_curved_geometry.py` covers a
14
+ sphere, a `cylinder_between` cylinder, a box, and a tampered IFC report.
15
+ Approval: `specrepo/approved/2026-10-08-curved-geometry-ifc-bounds/` (workspace).
16
+
17
+ The history below is kept as it was written.
18
+
2
19
 
3
20
  Status: **mechanism confirmed, fix known — not yet verified against this
4
21
  repo's own source.** A later sandbox-agent attempt on the same project (see
@@ -90,7 +90,9 @@ See `docs/two-tier-contract.md` for what "Tier 1" and "Tier 2" mean.
90
90
  ## Compatibility verification
91
91
 
92
92
  The `toolchain-matrix` CI job (`.github/workflows/ci.yml`) installs every
93
- capability group across `{ubuntu-latest, macos-latest} × {3.12, 3.13}`, runs
93
+ capability group across `{ubuntu-latest, macos-latest} × {3.12, 3.13}` on
94
+ version tags and manual runs (the release path; pushes and pull requests
95
+ run `core` and `all` on Linux for both Pythons), runs
94
96
  `pip check`, imports every library the group declares, and — for `all` — runs
95
97
  a Tier-2 interop smoke (a shape crosses build123d → `geometry.tessellate` →
96
98
  trimesh → ifcopenshell read-back → ezdxf) plus the no-GUI assertion. It
@@ -14,7 +14,7 @@ from xml.etree import ElementTree
14
14
 
15
15
  from .determinism import semantic_hash, sha256_file
16
16
  from .exceptions import ArtifactIntegrityError, BuildExportError
17
- from .manifests import load_json_document, validate_json_document
17
+ from .manifests import design_semantic_projection, load_json_document, validate_json_document
18
18
  from .validation import ValidationIssue
19
19
 
20
20
  BUILD_MANIFEST_RELATIVE = "manifests/build-manifest.json"
@@ -25,6 +25,7 @@ _EXPECTED_REPRESENTATION_TYPE = {None: "Tessellation", "extruded_profile": "Swep
25
25
 
26
26
  @dataclass(frozen=True, slots=True)
27
27
  class ArtifactRecord:
28
+ """One generated file: its path, size, SHA-256, media type and producer."""
28
29
  path: str
29
30
  size: int
30
31
  sha256: str
@@ -37,6 +38,7 @@ class ArtifactRecord:
37
38
 
38
39
  @dataclass(frozen=True, slots=True)
39
40
  class VerificationResult:
41
+ """The outcome of ``verify_build_output``: whether the output matches its manifest, and any issues."""
40
42
  ok: bool
41
43
  output_root: Path
42
44
  issues: tuple[ValidationIssue, ...]
@@ -48,6 +50,7 @@ class VerificationResult:
48
50
 
49
51
  @dataclass(frozen=True, slots=True)
50
52
  class PackageBuildInfo:
53
+ """The installed python-cad-tools distribution's version and build provenance."""
51
54
  schema_id: Literal["urn:python-cad-tools:schema:package-build-info:1"]
52
55
  schema_version: Literal[1]
53
56
  distribution: Literal["python-cad-tools"]
@@ -58,6 +61,7 @@ class PackageBuildInfo:
58
61
 
59
62
 
60
63
  def load_build_manifest(path: Path) -> dict[str, Any]:
64
+ """Read and schema-check a build manifest JSON file."""
61
65
  value = validate_json_document(path)
62
66
  if value["schema_id"] != "urn:python-cad-tools:schema:build-manifest:1":
63
67
  raise ArtifactIntegrityError(f"Not a build manifest: {path}")
@@ -65,6 +69,7 @@ def load_build_manifest(path: Path) -> dict[str, Any]:
65
69
 
66
70
 
67
71
  def load_design_manifest(path: Path) -> dict[str, Any]:
72
+ """Read and schema-check a design manifest JSON file."""
68
73
  value = validate_json_document(path)
69
74
  if value["schema_id"] != "urn:python-cad-tools:schema:design-manifest:1":
70
75
  raise ArtifactIntegrityError(f"Not a design manifest: {path}")
@@ -153,9 +158,8 @@ def verify_output_root(output_root: Path, project_root: Path | None = None) -> V
153
158
  _verify_sources(project_root, document)
154
159
  selected = _selected_formats(document)
155
160
  design = load_design_manifest(output_root / "manifests/design-manifest.json")
156
- design_without_hash = dict(design)
157
- recorded_design_hash = design_without_hash.pop("semantic_hash", None)
158
- if recorded_design_hash != semantic_hash(design_without_hash):
161
+ recorded_design_hash = design.get("semantic_hash")
162
+ if recorded_design_hash != semantic_hash(design_semantic_projection(design)):
159
163
  raise ArtifactIntegrityError("Design manifest semantic_hash does not reproduce")
160
164
  if document["design_semantic_hash"] != design["semantic_hash"]:
161
165
  raise ArtifactIntegrityError("Build and design manifest semantic hashes disagree")
@@ -172,6 +176,7 @@ def verify_output_root(output_root: Path, project_root: Path | None = None) -> V
172
176
 
173
177
 
174
178
  def verify_build_output(project_root: Path) -> VerificationResult:
179
+ """Check that a project's generated output still matches its build manifest."""
175
180
  from ._locking import project_lock
176
181
  from ._transaction import recover_promotion
177
182
  from .project_config import load_project_config, output_path, resolve_project_root
@@ -185,6 +190,7 @@ def verify_build_output(project_root: Path) -> VerificationResult:
185
190
 
186
191
 
187
192
  def get_package_build_info() -> PackageBuildInfo:
193
+ """Return the installed distribution's build information."""
188
194
  try:
189
195
  document = json.loads(resources.files("python_cad_tools").joinpath("build-info.json").read_text(encoding="utf-8"))
190
196
  except (FileNotFoundError, json.JSONDecodeError) as error:
@@ -386,7 +392,11 @@ def _reconcile_formats(root: Path, formats: tuple[str, ...]) -> None:
386
392
  for item in elements
387
393
  if item["physical"] and "ifc" in item["export_formats"] and item["ifc_class"] is not None
388
394
  ]
389
- _require_matching_bounds("IFC", report["bounds_mm"], _combined_manifest_bounds(expected_elements))
395
+ # Tessellated IFC bodies are meshes; compare them with the same mesh, recorded in the
396
+ # manifest as body_bounds_mm (0.1.18). Older manifests fall back to the exact bounds.
397
+ _require_matching_bounds(
398
+ "IFC", report["bounds_mm"], _combined_manifest_bounds(expected_elements, key="body_bounds_mm")
399
+ )
390
400
  _reconcile_ifc_extensions(root, formats, report, expected_elements)
391
401
  if "glb" in formats:
392
402
  from .exporters.glb import glb_json
@@ -536,14 +546,15 @@ def _normalized_text(value: str) -> str:
536
546
  return " ".join(value.split())
537
547
 
538
548
 
539
- def _combined_manifest_bounds(elements: list[dict[str, Any]]) -> list[float]:
549
+ def _combined_manifest_bounds(elements: list[dict[str, Any]], key: str = "bounds_mm") -> list[float]:
540
550
  if not elements:
541
551
  return [0.0] * 6
552
+ values = [item.get(key) or item["bounds_mm"] for item in elements]
542
553
  return [
543
- round(min(float(item["bounds_mm"][index]) for item in elements), 6)
554
+ round(min(float(value[index]) for value in values), 6)
544
555
  for index in range(3)
545
556
  ] + [
546
- round(max(float(item["bounds_mm"][index]) for item in elements), 6)
557
+ round(max(float(value[index]) for value in values), 6)
547
558
  for index in range(3, 6)
548
559
  ]
549
560
 
@@ -22,6 +22,7 @@ from .determinism import semantic_hash, sha256_file, write_json
22
22
  from .exceptions import BuildExportError, ModelValidationError, ProjectConfigError, UnsafePathError
23
23
  from .exporters import GlbExporter, IfcExporter, QuantityExporter, StepExporter
24
24
  from .exporters.drawings import DrawingExporter
25
+ from .geometry import shared_tessellation
25
26
  from .manifests import build_manifest_document, design_manifest, write_preinventory_manifests
26
27
  from .project_config import FORMAT_ORDER, load_project_config, output_path, resolve_project_root
27
28
  from .validation import ValidationIssue, fatal_issues
@@ -31,18 +32,21 @@ type FormatName = Literal["step", "ifc", "glb", "drawings", "quantities"]
31
32
 
32
33
  @dataclass(frozen=True, slots=True)
33
34
  class BuildOptions:
35
+ """Options for ``build_project``: the project root and the formats to build (default: the project's own)."""
34
36
  project_root: Path
35
37
  formats: tuple[FormatName, ...] | None = None
36
38
 
37
39
 
38
40
  @dataclass(frozen=True, slots=True)
39
41
  class ValidationOptions:
42
+ """Options for ``validate_project``: the project root and the formats to check (default: the project's own)."""
40
43
  project_root: Path
41
44
  formats: tuple[FormatName, ...] | None = None
42
45
 
43
46
 
44
47
  @dataclass(frozen=True, slots=True)
45
48
  class BuildResult:
49
+ """What ``build_project`` produced: its output folder, artifacts, build manifest and hashes."""
46
50
  project_root: Path
47
51
  output_root: Path
48
52
  formats: tuple[FormatName, ...]
@@ -56,6 +60,7 @@ class BuildResult:
56
60
 
57
61
  @dataclass(frozen=True, slots=True)
58
62
  class ValidationReport:
63
+ """The issues ``validate_project`` found; ``ok`` is true when none is fatal."""
59
64
  project_root: Path
60
65
  formats: tuple[FormatName, ...]
61
66
  issues: tuple[ValidationIssue, ...]
@@ -78,11 +83,12 @@ EXPORTERS: dict[str, type[Any]] = {
78
83
 
79
84
 
80
85
  def build_project(options: BuildOptions) -> BuildResult:
86
+ """Build the project's requested formats into its output folder and return the result."""
81
87
  if not isinstance(options, BuildOptions):
82
88
  raise TypeError("build_project expects BuildOptions")
83
89
  requested = _validate_requested_formats(options.formats)
84
90
  root = resolve_project_root(options.project_root)
85
- with project_execution():
91
+ with project_execution(), shared_tessellation():
86
92
  with project_lock(root):
87
93
  config = load_project_config(root)
88
94
  formats = config.default_formats if requested is None else requested
@@ -158,6 +164,7 @@ def build_project(options: BuildOptions) -> BuildResult:
158
164
 
159
165
 
160
166
  def validate_project(options: ValidationOptions) -> ValidationReport:
167
+ """Load the project's model and check it without writing any artifacts."""
161
168
  if not isinstance(options, ValidationOptions):
162
169
  raise TypeError("validate_project expects ValidationOptions")
163
170
  requested = _validate_requested_formats(options.formats)
@@ -173,7 +180,7 @@ def validate_project(options: ValidationOptions) -> ValidationReport:
173
180
  formats=formats,
174
181
  issues=loaded.issues,
175
182
  source_set_hash=source_set_hash,
176
- design_semantic_hash=design_manifest(loaded.model)["semantic_hash"],
183
+ design_semantic_hash=design_manifest(loaded.model, include_body_bounds=False)["semantic_hash"],
177
184
  annotation_provider_id=(
178
185
  None if loaded.annotations is None else loaded.annotations.provider_id
179
186
  ),
@@ -181,6 +188,7 @@ def validate_project(options: ValidationOptions) -> ValidationReport:
181
188
 
182
189
 
183
190
  def clean_project(project_root: Path) -> None:
191
+ """Remove the project's generated output folder."""
184
192
  reject_nested_project_execution()
185
193
  root = resolve_project_root(project_root)
186
194
  config = load_project_config(root)
@@ -15,6 +15,7 @@ if TYPE_CHECKING:
15
15
 
16
16
  @dataclass(frozen=True, slots=True)
17
17
  class BuildContext:
18
+ """What ``build_model`` receives: the project root, its loaded ``config`` and source revision, with recorded read-only access to declared sources."""
18
19
  project_root: Path
19
20
  config: Any
20
21
  source_revision: str | None
@@ -57,6 +58,7 @@ class BuildContext:
57
58
 
58
59
  @dataclass(frozen=True, slots=True)
59
60
  class DrawingContext:
61
+ """What a drawing annotation provider receives: the built model and its sheets, in millimetres."""
60
62
  project_root: Path
61
63
  config: Any
62
64
  model: DesignModel
@@ -19,6 +19,8 @@ type DrawingStyleToken = Literal[
19
19
 
20
20
  @dataclass(frozen=True, slots=True)
21
21
  class DrawingSheet:
22
+ """One drawing view: its id, view kind, projection origin and axes, and projected bounds in millimetres."""
23
+
22
24
  sheet_id: str
23
25
  view_id: Literal["plan", "front", "side", "section"]
24
26
  origin_mm: tuple[float, float, float]
@@ -29,6 +31,8 @@ class DrawingSheet:
29
31
 
30
32
  @dataclass(frozen=True, slots=True)
31
33
  class Line:
34
+ """A straight annotation line on a sheet, in projected millimetres."""
35
+
32
36
  id: str
33
37
  sheet_id: str
34
38
  start: Point2
@@ -38,6 +42,8 @@ class Line:
38
42
 
39
43
  @dataclass(frozen=True, slots=True)
40
44
  class Polyline:
45
+ """An open or closed annotation polyline on a sheet, in projected millimetres."""
46
+
41
47
  id: str
42
48
  sheet_id: str
43
49
  points: tuple[Point2, ...]
@@ -47,6 +53,8 @@ class Polyline:
47
53
 
48
54
  @dataclass(frozen=True, slots=True)
49
55
  class Text:
56
+ """Annotation text placed on a sheet, with its height in millimetres and rotation in degrees."""
57
+
50
58
  id: str
51
59
  sheet_id: str
52
60
  position: Point2
@@ -58,6 +66,8 @@ class Text:
58
66
 
59
67
  @dataclass(frozen=True, slots=True)
60
68
  class Dimension:
69
+ """A labelled dimension between two sheet points, offset in millimetres."""
70
+
61
71
  id: str
62
72
  sheet_id: str
63
73
  start: Point2
@@ -69,6 +79,8 @@ class Dimension:
69
79
 
70
80
  @dataclass(frozen=True, slots=True)
71
81
  class SectionCallout:
82
+ """A section cut line on a sheet that refers to the sheet showing that section."""
83
+
72
84
  id: str
73
85
  sheet_id: str
74
86
  start: Point2
@@ -80,6 +92,8 @@ class SectionCallout:
80
92
 
81
93
  @dataclass(frozen=True, slots=True)
82
94
  class ElevationMarker:
95
+ """A marker on a sheet that refers to the sheet showing that elevation."""
96
+
83
97
  id: str
84
98
  sheet_id: str
85
99
  position: Point2
@@ -90,12 +104,16 @@ class ElevationMarker:
90
104
 
91
105
  @dataclass(frozen=True, slots=True)
92
106
  class TableRow:
107
+ """One row of an annotation ``Table``."""
108
+
93
109
  id: str
94
110
  cells: tuple[str, ...]
95
111
 
96
112
 
97
113
  @dataclass(frozen=True, slots=True)
98
114
  class Table:
115
+ """A titled annotation table placed on a sheet."""
116
+
99
117
  id: str
100
118
  sheet_id: str
101
119
  position: Point2
@@ -109,12 +127,16 @@ type AnnotationPrimitive = Line | Polyline | Text | Dimension | SectionCallout |
109
127
 
110
128
  @dataclass(frozen=True, slots=True)
111
129
  class SheetAnnotations:
130
+ """All annotations for one sheet."""
131
+
112
132
  sheet_id: str
113
133
  annotations: tuple[AnnotationPrimitive, ...]
114
134
 
115
135
 
116
136
  @dataclass(frozen=True, slots=True)
117
137
  class DrawingAnnotationSet:
138
+ """What a drawing annotation provider returns: annotations per sheet."""
139
+
118
140
  provider_id: str
119
141
  sheets: tuple[SheetAnnotations, ...]
120
142
 
@@ -15,6 +15,8 @@ GeometryKind = Literal["solid", "shell", "wire", "edge", "reference"]
15
15
 
16
16
  @dataclass(frozen=True, slots=True)
17
17
  class MaterialSpec:
18
+ """A material: id, display name, category, RGB colour in 0-1 and optional density in kg/m3."""
19
+
18
20
  id: str
19
21
  name: str
20
22
  category: str
@@ -25,12 +27,16 @@ class MaterialSpec:
25
27
 
26
28
  @dataclass(frozen=True, slots=True)
27
29
  class Placement:
30
+ """An element's recorded position (millimetres) and XYZ rotation (degrees); it does not move the geometry, which must already be in place."""
31
+
28
32
  translation_mm: tuple[float, float, float] = (0.0, 0.0, 0.0)
29
33
  rotation_deg_xyz: tuple[float, float, float] = (0.0, 0.0, 0.0)
30
34
 
31
35
 
32
36
  @dataclass(frozen=True, slots=True)
33
37
  class Dimensions:
38
+ """An element's declared size in millimetres; every value given must be finite and positive."""
39
+
34
40
  length_mm: float | None = None
35
41
  width_mm: float | None = None
36
42
  height_mm: float | None = None
@@ -46,6 +52,8 @@ class Dimensions:
46
52
 
47
53
  @dataclass(frozen=True, slots=True)
48
54
  class IfcMapping:
55
+ """The IFC class and predefined type an element exports as, or why it is excluded from IFC."""
56
+
49
57
  ifc_class: str | None
50
58
  predefined_type: str | None = None
51
59
  exclude_reason: str | None = None
@@ -68,6 +76,8 @@ class Opening:
68
76
 
69
77
  @dataclass(slots=True)
70
78
  class DesignElement:
79
+ """One model element with a stable id; physical elements need solid geometry and a material, and colours use RGB in 0-1."""
80
+
71
81
  id: str
72
82
  name: str
73
83
  category: str
@@ -98,6 +108,8 @@ class DesignElement:
98
108
 
99
109
  @dataclass(slots=True)
100
110
  class DesignModel:
111
+ """The whole model a project's ``build_model`` returns: its elements in millimetres, X right, Y away, Z up."""
112
+
101
113
  id: str
102
114
  name: str
103
115
  artifact_stem: str
@@ -17,7 +17,7 @@ from ifcopenshell import ifcopenshell_wrapper
17
17
  from ..determinism import normalized_build_epoch, write_json
18
18
  from ..elements import DesignElement, Opening
19
19
  from ..exceptions import BuildExportError, ModelValidationError
20
- from ..geometry import bounds, tessellate
20
+ from ..geometry import IFC_TESSELLATION, bounds, tessellate
21
21
  from ..recipes import (
22
22
  CircleProfile,
23
23
  DifferenceRecipe,
@@ -326,7 +326,7 @@ def _build_representation(file, context, element: DesignElement) -> tuple[Any, s
326
326
  BREP instead.
327
327
  """
328
328
  if element.recipe is None:
329
- vertices, triangles = tessellate(element.geometry, 0.5, 0.25)
329
+ vertices, triangles = tessellate(element.geometry, *IFC_TESSELLATION)
330
330
  points = file.createIfcCartesianPointList3D(vertices)
331
331
  face_set = file.createIfcTriangulatedFaceSet(
332
332
  points,
@@ -482,7 +482,7 @@ def _add_opening(file, context, host_product, storey, element, opening: Opening)
482
482
  The host element's ``geometry`` stays authoritative for every other
483
483
  format; the framework does not boolean-subtract the opening.
484
484
  """
485
- vertices, triangles = tessellate(opening.geometry, 0.5, 0.25)
485
+ vertices, triangles = tessellate(opening.geometry, *IFC_TESSELLATION)
486
486
  points = file.createIfcCartesianPointList3D(vertices)
487
487
  face_set = file.createIfcTriangulatedFaceSet(
488
488
  points, None, True, [[index + 1 for index in triangle] for triangle in triangles], None