python-cad-tools 0.1.20__tar.gz → 0.1.21__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 (273) hide show
  1. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/CHANGELOG.md +14 -0
  2. {python_cad_tools-0.1.20/src/python_cad_tools.egg-info → python_cad_tools-0.1.21}/PKG-INFO +1 -1
  3. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/docs/neutral-model.md +1 -1
  4. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/validation.py +60 -0
  5. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21/src/python_cad_tools.egg-info}/PKG-INFO +1 -1
  6. python_cad_tools-0.1.21/src/python_cad_tools.egg-info/scm_version.json +8 -0
  7. python_cad_tools-0.1.20/src/python_cad_tools.egg-info/scm_version.json +0 -8
  8. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/.gitattributes +0 -0
  9. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/.githooks/pre-push +0 -0
  10. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/.github/workflows/ci.yml +0 -0
  11. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/.github/workflows/downstream-compatibility.yml +0 -0
  12. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/.github/workflows/release-candidate.yml +0 -0
  13. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/.github/workflows/release.yml +0 -0
  14. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/.gitignore +0 -0
  15. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/.opencode/commands/autocommit.md +0 -0
  16. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/.opencode/tools/specrepo-autocommit.js +0 -0
  17. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/.opencode/tools/specrepo-autocommit.py +0 -0
  18. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/AGENTS.md +0 -0
  19. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/CLAUDE.md +0 -0
  20. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/LICENSE +0 -0
  21. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/MANIFEST.in +0 -0
  22. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/README.md +0 -0
  23. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/docs/build-semantics.md +0 -0
  24. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/docs/drawing-extensions.md +0 -0
  25. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/docs/manifests.md +0 -0
  26. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/docs/project-configuration.md +0 -0
  27. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/docs/public-api.md +0 -0
  28. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/docs/spikes/curved-geometry-ifc-bounds.md +0 -0
  29. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/docs/spikes/format-feasibility.md +0 -0
  30. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/docs/toolchain.md +0 -0
  31. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/docs/two-tier-contract.md +0 -0
  32. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/docs/viewer-delivery.md +0 -0
  33. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/pyproject.toml +0 -0
  34. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/setup.cfg +0 -0
  35. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/__init__.py +0 -0
  36. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/__main__.py +0 -0
  37. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_locking.py +0 -0
  38. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_project_loader.py +0 -0
  39. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_project_state.py +0 -0
  40. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_scaffold.py +0 -0
  41. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_transaction.py +0 -0
  42. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/app.webmanifest +0 -0
  43. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/asset-manifest.json +0 -0
  44. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/animationGroup-y0vxJTHi.js +0 -0
  45. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/bakedVertexAnimation-BBtOjYgD.js +0 -0
  46. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/basisTextureLoader-C0CWWK6C.js +0 -0
  47. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/brdfTextureTools-BK5sbjI4.js +0 -0
  48. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/bumpFragment-DA8EdzWp.js +0 -0
  49. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/bumpVertex-C-Tz5-on.js +0 -0
  50. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/bumpVertexDeclaration-DcJYzNbJ.js +0 -0
  51. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/clipPlaneFragment-TSEtEMNd.js +0 -0
  52. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/clipPlaneVertex-uZlnoaiC.js +0 -0
  53. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/cubemapToSphericalPolynomial-CbpdsBi-.js +0 -0
  54. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/dds-DTJCjwtR.js +0 -0
  55. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/dds.pure-GxPY_zfe.js +0 -0
  56. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/ddsTextureLoader-CksmWoIY.js +0 -0
  57. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/default.fragment-CLdN55aJ.js +0 -0
  58. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/default.vertex-hpVkU2OZ.js +0 -0
  59. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/defaultUboDeclaration-B-2Y6yF1.js +0 -0
  60. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/dumpTools-2Vxp-avt.js +0 -0
  61. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/envTextureLoader-BJ6o68xV.js +0 -0
  62. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/exrTextureLoader-EGHqxheE.js +0 -0
  63. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphApplyForceBlock-DAS01LnC.js +0 -0
  64. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphApplyImpulseBlock-CMzcV63U.js +0 -0
  65. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphArrayIndexBlock-BnBgFyIE.js +0 -0
  66. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphBezierCurveEasingBlock-BuVUi2RL.js +0 -0
  67. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphBinaryOperationBlock-CVGmsw8x.js +0 -0
  68. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphBranchBlock-BfIcR38b.js +0 -0
  69. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphCachedOperationBlock-BItwxOg_.js +0 -0
  70. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphCancelDelayBlock-DabMn7mT.js +0 -0
  71. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphCodeExecutionBlock-B9nrso5H.js +0 -0
  72. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphConditionalDataBlock-BTfkFqJa.js +0 -0
  73. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphConsoleLogBlock-ZKRRrx3V.js +0 -0
  74. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphConstantBlock-Dynbc9i5.js +0 -0
  75. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphContextBlock-aaa4bUjB.js +0 -0
  76. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphCounterBlock-DHQ9YaXX.js +0 -0
  77. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphDataSwitchBlock-DCcjQH_2.js +0 -0
  78. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphDebounceBlock-CHLipwBM.js +0 -0
  79. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphDebugBlock-B7BE97Pj.js +0 -0
  80. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphDoNBlock-cMK6KEZp.js +0 -0
  81. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphEasingBlock-B4WasDy3.js +0 -0
  82. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphFlipFlopBlock-DrbNVT2u.js +0 -0
  83. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphForLoopBlock-Bbur2Xn2.js +0 -0
  84. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphFunctionReferenceBlock-CnlGraT6.js +0 -0
  85. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphGLTFDataProvider-D_p9Vc3n.js +0 -0
  86. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphGetAngularVelocityBlock-CoO6JHmy.js +0 -0
  87. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphGetAssetBlock-JakaK1JL.js +0 -0
  88. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphGetLinearVelocityBlock-BGL2RtAb.js +0 -0
  89. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphGetPhysicsMassPropertiesBlock-CxIjatfx.js +0 -0
  90. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphGetPropertyBlock-DT-QXVu_.js +0 -0
  91. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphGetSoundVolumeBlock-C4LKSI5R.js +0 -0
  92. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphGetVariableBlock-DIlaVi8M.js +0 -0
  93. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphIndexOfBlock-DYf_o9uE.js +0 -0
  94. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphInterpolationBlock-tG1kO4s_.js +0 -0
  95. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphIsKeyPressedBlock-D6ExxkWF.js +0 -0
  96. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphIsSoundPlayingBlock-vPEvDIRc.js +0 -0
  97. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphJsonPointerParserBlock-Af-cdpFu.js +0 -0
  98. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyDownEventBlock-BABAmIeL.js +0 -0
  99. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyUpEventBlock-BSUoekRK.js +0 -0
  100. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphKeyboardEventBlock-CZDsT79F.js +0 -0
  101. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphMathBlocks-UEv4tVyC.js +0 -0
  102. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphMathCombineExtractBlocks-CbwJeujD.js +0 -0
  103. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphMatrixMathBlocks-CJ0nrwFc.js +0 -0
  104. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphMeshPickEventBlock-CYCR7C7B.js +0 -0
  105. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphMultiGateBlock-tAD2s18w.js +0 -0
  106. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphPauseAnimationBlock-C1yfh7U4.js +0 -0
  107. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphPauseSoundBlock-B8T3Qxmk.js +0 -0
  108. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphPhysicsCollisionEventBlock-B4vsEIEQ.js +0 -0
  109. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphPlayAnimationBlock-BuU8u7bh.js +0 -0
  110. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphPlaySoundBlock-OsFJerGp.js +0 -0
  111. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerDownEventBlock-B4myfwzY.js +0 -0
  112. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerMoveEventBlock-C7kNYXVC.js +0 -0
  113. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerOutEventBlock-BwL1k9K3.js +0 -0
  114. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerOverEventBlock-D7uPUz3m.js +0 -0
  115. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphPointerUpEventBlock-h2k1otta.js +0 -0
  116. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphReceiveCustomEventBlock-CKsih9DU.js +0 -0
  117. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSceneReadyEventBlock-MoEL2OgG.js +0 -0
  118. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSceneTickEventBlock-DkhjsuEd.js +0 -0
  119. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSendCustomEventBlock-CDJDoId5.js +0 -0
  120. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSequenceBlock-CKvAcfGB.js +0 -0
  121. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSetAngularVelocityBlock-DUVgv52d.js +0 -0
  122. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSetDelayBlock-B0LkcVpW.js +0 -0
  123. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSetLinearVelocityBlock-DdFINyIs.js +0 -0
  124. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSetPhysicsMotionTypeBlock-B_GSDzn3.js +0 -0
  125. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSetPropertyBlock-5WKrlvaE.js +0 -0
  126. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSetSoundVolumeBlock-CdnrYD5B.js +0 -0
  127. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSetVariableBlock-DD5gsKis.js +0 -0
  128. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSoundEndedEventBlock-fKBoAQlt.js +0 -0
  129. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphStopAnimationBlock-CDm85_Y9.js +0 -0
  130. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphStopSoundBlock-BY77RYv7.js +0 -0
  131. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphSwitchBlock-BLuZLMgz.js +0 -0
  132. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphThrottleBlock-BoV3UuLi.js +0 -0
  133. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphTransformCoordinatesSystemBlock-BO46AA3F.js +0 -0
  134. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphTypeToTypeBlocks-_O7ljeb3.js +0 -0
  135. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphUnaryOperationBlock-C1RBwiu1.js +0 -0
  136. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphVectorMathBlocks-CRPoi5bR.js +0 -0
  137. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphWaitAllBlock-B4u-Lnoz.js +0 -0
  138. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/flowGraphWhileLoopBlock-C2wNz7MU.js +0 -0
  139. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/fogFragment-DAcG7TCQ.js +0 -0
  140. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting-DHOD58HS.js +0 -0
  141. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting-DIlhNWGI.js +0 -0
  142. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.fragment-Csz9k2lc.js +0 -0
  143. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.fragment-DyjC4p2I.js +0 -0
  144. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.vertex-BYdix1b9.js +0 -0
  145. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/gaussianSplatting.vertex-qaQwrhXF.js +0 -0
  146. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.fragment-BiVyc4nS.js +0 -0
  147. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.fragment-C9kJafLO.js +0 -0
  148. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.vertex-BRLme_YW.js +0 -0
  149. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/gaussianSplattingVoxel.vertex-DSPVps-_.js +0 -0
  150. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/geometry.fragment-BcBx-JUz.js +0 -0
  151. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/geometry.fragment-rcQdOa18.js +0 -0
  152. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/geometry.vertex-BTVcDQMd.js +0 -0
  153. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/geometry.vertex-BbL_FLfO.js +0 -0
  154. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/glowBlurPostProcess.fragment-BOrEH7qZ.js +0 -0
  155. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/glowMapGeneration.fragment-Dw2pELM9.js +0 -0
  156. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/glowMapGeneration.vertex-g4zSgWHl.js +0 -0
  157. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/glowMapMerge.fragment-BRI1RC0h.js +0 -0
  158. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/glowMapMerge.vertex-OYXhsO5y.js +0 -0
  159. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/harmonicsFunctions-B-rFa6Jw.js +0 -0
  160. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/hdrTextureLoader-BGQvgh0h.js +0 -0
  161. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/helperFunctions-CJuKh7zv.js +0 -0
  162. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/iesTextureLoader-hQPlzY89.js +0 -0
  163. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/index-Bi_hQlRi.css +0 -0
  164. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/index-aS20qDZO.js +0 -0
  165. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/kernelBlur.fragment-Bkkqf9Gf.js +0 -0
  166. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/kernelBlur.fragment-gsnhhxsW.js +0 -0
  167. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/kernelBlur.vertex-CuVvtzKn.js +0 -0
  168. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/kernelBlur.vertex-Di3ETd02.js +0 -0
  169. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/kernelBlurVaryingDeclaration-D8-BThIr.js +0 -0
  170. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/kernelBlurVaryingDeclaration-lHduxGLy.js +0 -0
  171. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/ktxTextureLoader-CsB3T93v.js +0 -0
  172. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/lightFragment-DomeLrOQ.js +0 -0
  173. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/logDepthDeclaration-DdSMU1vE.js +0 -0
  174. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/logDepthVertex-CIYc6FKU.js +0 -0
  175. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/mainUVVaryingDeclaration-CinwtRdE.js +0 -0
  176. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/mesh.vertexData.functions-ayNlGC5K.js +0 -0
  177. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/meshUboDeclaration-BHuQNGCy.js +0 -0
  178. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/oitFragment-CG7kMCvU.js +0 -0
  179. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/openpbr.fragment-CRlYBc_-.js +0 -0
  180. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/openpbr.fragment-Csz9EYJi.js +0 -0
  181. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/openpbr.vertex-D8xRp_pg.js +0 -0
  182. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/openpbr.vertex-DWzGweC9.js +0 -0
  183. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/openpbrMaterial.pure-BVsTXLPP.js +0 -0
  184. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/openpbrMaterialLoadingAdapter-Cl2qUNz7.js +0 -0
  185. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/openpbrTransmissionLayerData-C3FnopjH.js +0 -0
  186. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/openpbrTransmissionLayerData-MOccHJLS.js +0 -0
  187. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/openpbrUboDeclaration-Bd8N4mLs.js +0 -0
  188. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/openpbrUboDeclaration-DbIcgURU.js +0 -0
  189. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/packingFunctions-B-RyPnvp.js +0 -0
  190. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/packingFunctions-B_LoQGE_.js +0 -0
  191. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/pass.fragment-CosRVAJR.js +0 -0
  192. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/passCube.fragment-ByQLKcal.js +0 -0
  193. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/passCube.fragment-COrMlz4L.js +0 -0
  194. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/pbr.fragment-Dp9qP0ik.js +0 -0
  195. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/pbr.vertex-BEhyQo04.js +0 -0
  196. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/pbrBRDFFunctions-MD5J9kNB.js +0 -0
  197. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/pbrDebug-BMEohefD.js +0 -0
  198. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/pbrIBLFunctions-BNSg1TYL.js +0 -0
  199. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/pbrMaterial.pure-CmT8POVY.js +0 -0
  200. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/pbrMaterialLoadingAdapter-B9wrRf4Y.js +0 -0
  201. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/pbrUboDeclaration-CaZ5IiXn.js +0 -0
  202. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/postprocess.vertex-6O8OKxg1.js +0 -0
  203. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/procedural.vertex-CnLTJ0GC.js +0 -0
  204. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/procedural.vertex-CsPpF8ex.js +0 -0
  205. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/reflectionFunction-FOkl7zGy.js +0 -0
  206. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/rgbdDecode.fragment-B3rgzhU8.js +0 -0
  207. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/rgbdEncode.fragment-BQbjknQm.js +0 -0
  208. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/rgbdEncode.fragment-DyCYq3cD.js +0 -0
  209. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/sceneUboDeclaration-qgAWTN28.js +0 -0
  210. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/textureProcessor.fragment-DNVQK8Xr.js +0 -0
  211. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/textureProcessor.fragment-pAIEAh33.js +0 -0
  212. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/tgaTextureLoader-BE-ozdBC.js +0 -0
  213. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/assets/vertexColorMixing-B7eY1nal.js +0 -0
  214. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/favicon.svg +0 -0
  215. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/index.html +0 -0
  216. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/_viewer_static/sw.js +0 -0
  217. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/artifacts.py +0 -0
  218. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/build-info.json +0 -0
  219. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/build.py +0 -0
  220. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/cli.py +0 -0
  221. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/context.py +0 -0
  222. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/determinism.py +0 -0
  223. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/drawings/__init__.py +0 -0
  224. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/drawings/_catalog.py +0 -0
  225. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/drawings/_validation.py +0 -0
  226. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/elements.py +0 -0
  227. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exceptions.py +0 -0
  228. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/__init__.py +0 -0
  229. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/base.py +0 -0
  230. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/drawings/__init__.py +0 -0
  231. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/drawings/annotations.py +0 -0
  232. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/drawings/dxf.py +0 -0
  233. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/drawings/model.py +0 -0
  234. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/drawings/pdf.py +0 -0
  235. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/drawings/primitives.py +0 -0
  236. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/drawings/projection.py +0 -0
  237. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/drawings/svg.py +0 -0
  238. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/glb.py +0 -0
  239. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/ifc.py +0 -0
  240. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/quantities.py +0 -0
  241. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/renders.py +0 -0
  242. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/exporters/step.py +0 -0
  243. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/geometry.py +0 -0
  244. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/manifests.py +0 -0
  245. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/project_config.py +0 -0
  246. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/py.typed +0 -0
  247. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/recipes.py +0 -0
  248. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/runtime_sync.py +0 -0
  249. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/schemas/build-manifest-1.json +0 -0
  250. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/schemas/design-manifest-1.json +0 -0
  251. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/schemas/download-manifest-2.json +0 -0
  252. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/schemas/drawing-annotations-1.json +0 -0
  253. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/schemas/glb-manifest-1.json +0 -0
  254. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/schemas/ifc-validation-1.json +0 -0
  255. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/schemas/quantities-1.json +0 -0
  256. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/schemas/run-metadata-1.json +0 -0
  257. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/schemas/site-metadata-1.json +0 -0
  258. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/schemas/step-validation-1.json +0 -0
  259. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/site.py +0 -0
  260. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/templates/project/.gitignore +0 -0
  261. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/templates/project/README.md +0 -0
  262. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/templates/project/config.py +0 -0
  263. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/templates/project/drawing_annotations.py +0 -0
  264. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/templates/project/generated/.gitkeep +0 -0
  265. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/templates/project/model.py +0 -0
  266. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/templates/project/pyproject.toml +0 -0
  267. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools/units.py +0 -0
  268. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools.egg-info/SOURCES.txt +0 -0
  269. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools.egg-info/dependency_links.txt +0 -0
  270. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools.egg-info/entry_points.txt +0 -0
  271. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools.egg-info/requires.txt +0 -0
  272. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools.egg-info/scm_file_list.json +0 -0
  273. {python_cad_tools-0.1.20 → python_cad_tools-0.1.21}/src/python_cad_tools.egg-info/top_level.txt +0 -0
@@ -7,6 +7,20 @@ stable release is published.
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.1.21] - 2026-10-27
11
+
12
+ ### Added
13
+
14
+ - `validate` (and so `build`) now fails a model whose parts were never moved
15
+ into place:
16
+ - `placement-unapplied`: a physical solid whose non-zero
17
+ `Placement.translation_mm` lies outside its own bounds. `Placement`
18
+ records a position and never moves geometry, so the part would export
19
+ where it was built. Build the solid in place instead, for example with
20
+ `box(..., origin=...)` or `shape.moved(Location((x, y, z)))`.
21
+ - `stacked-elements`: three or more physical solids with exactly the same
22
+ bounds, which is almost always parts left at the origin.
23
+
10
24
  ## [0.1.20] - 2026-10-21
11
25
 
12
26
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-cad-tools
3
- Version: 0.1.20
3
+ Version: 0.1.21
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,7 +16,7 @@ dimensions), and the validator invocation model. See
16
16
  | `category` | `str` | Free-text classification, exported as `ObjectType` in IFC. |
17
17
  | `geometry` | `Any` | A build123d-compatible solid, shell, wire, or edge. Required and opaque — the framework does not restrict how it was built. May be `None` when `recipe` is present; the framework materializes it. |
18
18
  | `geometry_kind` | `"solid" \| "shell" \| "wire" \| "edge" \| "reference"` | Declares the geometry's topological kind. Physical elements must be `"solid"`. |
19
- | `placement` | `Placement` | Translation (mm) and rotation (degrees, XYZ) applied on top of `geometry`'s own coordinates. |
19
+ | `placement` | `Placement` | The element's recorded position: translation (mm) and rotation (degrees, XYZ). It does **not** move `geometry`, which must already be built in place (for example `box(..., origin=...)`); `validate` fails a solid whose non-zero translation lies outside its own bounds (`placement-unapplied`). |
20
20
  | `dimensions` | `Dimensions` | Declared, author-stated extents. Independent of the geometry's actual bounds; exported into `Pset_PythonCadDesign`. |
21
21
  | `material` | `MaterialSpec \| None` | Required for physical elements. Drives IFC material association and quantity mass calculation (`density_kg_m3`). |
22
22
  | `color_rgb` | `Color \| None` | Overrides the material color for this element's rendering/styling. |
@@ -73,6 +73,7 @@ def validate_model(model: DesignModel) -> list[ValidationIssue]:
73
73
  seen_instances: set[int] = set()
74
74
  for element in walked:
75
75
  issues.extend(_validate_element(element, seen_ids, seen_instances, known))
76
+ issues.extend(_validate_stacked(walked))
76
77
  for validator in model.validators:
77
78
  issues.extend(validator(model))
78
79
  return sorted(issues, key=lambda issue: (issue.severity, issue.code, issue.source_path or "", issue.element_id or ""))
@@ -137,6 +138,7 @@ def _validate_element(
137
138
  issues.append(
138
139
  ValidationIssue("dimensions", "error", "Declared dimensions must be finite and positive", element_id=element.id)
139
140
  )
141
+ issues.extend(_validate_placement_applied(element))
140
142
  if element.physical and element.material is None:
141
143
  issues.append(ValidationIssue("material", "error", "Physical elements require a material", element_id=element.id))
142
144
  if element.material is not None:
@@ -165,6 +167,64 @@ def _validate_element(
165
167
  return issues
166
168
 
167
169
 
170
+ #: Slack (mm) around a solid's bounds within which its recorded placement counts as applied.
171
+ _PLACEMENT_TOLERANCE_MM = 1.0
172
+ #: This many physical solids with the same bounds means parts were left where they were built.
173
+ _STACKED_MINIMUM = 3
174
+
175
+
176
+ def _validate_placement_applied(element: DesignElement) -> list[ValidationIssue]:
177
+ """``Placement`` records a position but never moves geometry. A physical
178
+ solid whose non-zero placement lies outside its own bounds was almost
179
+ certainly meant to be moved there and never was, so every exporter would
180
+ draw it at the wrong place."""
181
+ if not element.physical or element.geometry is None or not is_valid_solid(element.geometry):
182
+ return []
183
+ point = element.placement.translation_mm
184
+ if not all(isfinite(value) for value in point) or not any(point):
185
+ return []
186
+ extent = bounds(element.geometry)
187
+ low, high = extent[:3], extent[3:]
188
+ slack = _PLACEMENT_TOLERANCE_MM
189
+ if all(lo - slack <= value <= hi + slack for value, lo, hi in zip(point, low, high, strict=True)):
190
+ return []
191
+ return [
192
+ ValidationIssue(
193
+ "placement-unapplied",
194
+ "error",
195
+ f"Placement translation {tuple(round(value, 1) for value in point)} lies outside the geometry's bounds "
196
+ f"{tuple(round(value, 1) for value in extent)}; Placement does not move geometry, so build the solid "
197
+ "in place (for example box(..., origin=...) or shape.moved(Location((x, y, z))))",
198
+ element_id=element.id,
199
+ )
200
+ ]
201
+
202
+
203
+ def _validate_stacked(elements: list[DesignElement]) -> list[ValidationIssue]:
204
+ """Several physical solids with identical bounds sit on top of each other:
205
+ almost always parts that were built at the origin and never moved."""
206
+ groups: dict[tuple[float, ...], list[str]] = {}
207
+ for element in elements:
208
+ if element.physical and element.geometry is not None and is_valid_solid(element.geometry):
209
+ key = tuple(round(value, 1) for value in bounds(element.geometry))
210
+ groups.setdefault(key, []).append(element.id)
211
+ issues: list[ValidationIssue] = []
212
+ for key, ids in groups.items():
213
+ if len(ids) < _STACKED_MINIMUM:
214
+ continue
215
+ named = ", ".join(ids[:5]) + (f" and {len(ids) - 5} more" if len(ids) > 5 else "")
216
+ issues.append(
217
+ ValidationIssue(
218
+ "stacked-elements",
219
+ "error",
220
+ f"{len(ids)} physical elements occupy exactly the same bounds {key} ({named}); "
221
+ "move each solid to its own position",
222
+ element_id=ids[0],
223
+ )
224
+ )
225
+ return issues
226
+
227
+
168
228
  def _exported_to_ifc(element: DesignElement) -> bool:
169
229
  return (
170
230
  element.visible
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-cad-tools
3
- Version: 0.1.20
3
+ Version: 0.1.21
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
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "0.1.21",
3
+ "distance": 0,
4
+ "node": "g9515aec6eea3d761681fbb33b7ecdb4b2b65625a",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-10-27"
8
+ }
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "0.1.20",
3
- "distance": 0,
4
- "node": "g046b2866e1daf8a34ec5a982d0c30d56f8545483",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-10-21"
8
- }