openscad-cpp-evaluator 0.31.0__tar.gz → 0.31.2__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 (200) hide show
  1. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/PKG-INFO +1 -1
  2. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/mesh_check.hpp +18 -3
  3. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/pyproject.toml +1 -1
  4. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/import.cpp +27 -6
  5. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/primitives_3d.cpp +18 -10
  6. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/roof.cpp +10 -4
  7. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/surface.cpp +8 -6
  8. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/mesh_check.cpp +40 -15
  9. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_cli.cpp +44 -1
  10. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_import_export.cpp +45 -0
  11. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/.github/workflows/ci.yml +0 -0
  12. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/.github/workflows/wheels.yml +0 -0
  13. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/.gitignore +0 -0
  14. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/.gitmodules +0 -0
  15. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/CLAUDE.md +0 -0
  16. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/CMakeLists.txt +0 -0
  17. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/LICENSE +0 -0
  18. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/README.md +0 -0
  19. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/bindings/CMakeLists.txt +0 -0
  20. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/bindings/ast_to_py.cpp +0 -0
  21. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/bindings/module.cpp +0 -0
  22. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/cmake/embed_font.cmake +0 -0
  23. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/examples/CMakeLists.txt +0 -0
  24. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/examples/eval_perf_benchmark.cpp +0 -0
  25. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/examples/manifold_cache_reuse.cpp +0 -0
  26. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/examples/minimal_debugger.cpp +0 -0
  27. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  28. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/.gitignore +0 -0
  29. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  30. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  31. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/README.md +0 -0
  32. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  33. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  34. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  35. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  36. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  37. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  38. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  39. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  40. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  41. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  42. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  43. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  44. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  45. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  46. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  47. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  48. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/api.cpp +0 -0
  49. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  50. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  51. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  52. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  53. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  54. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  55. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  56. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  57. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  58. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  59. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  60. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  61. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  62. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  63. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  64. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  65. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/position.cpp +0 -0
  66. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  67. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  68. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  69. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  70. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  71. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  72. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  73. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  74. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  75. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  76. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  77. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  78. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  79. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  80. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  81. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  82. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  83. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  84. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  85. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  86. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  87. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  88. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  89. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  90. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  91. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  92. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  93. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  94. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
  95. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  96. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  97. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  98. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  99. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  100. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  101. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  102. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  103. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  104. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  105. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  106. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  107. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  108. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
  109. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/export.hpp +0 -0
  110. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  111. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  112. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  113. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  114. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  115. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  116. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  117. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  118. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  119. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
  120. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  121. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  122. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/value.hpp +0 -0
  123. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  124. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/python/openscad_cpp_evaluator/__init__.py +0 -0
  125. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/resources/fonts/LICENSE +0 -0
  126. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  127. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/CMakeLists.txt +0 -0
  128. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/booleans.cpp +0 -0
  129. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/builtins.hpp +0 -0
  130. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/call_args.cpp +0 -0
  131. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/color.cpp +0 -0
  132. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/control.cpp +0 -0
  133. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/extrude.cpp +0 -0
  134. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/function_builtins.cpp +0 -0
  135. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/modifiers.cpp +0 -0
  136. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/primitives_2d.cpp +0 -0
  137. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/registry.cpp +0 -0
  138. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/segments.cpp +0 -0
  139. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/text.cpp +0 -0
  140. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/topology.cpp +0 -0
  141. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/builtins/transforms.cpp +0 -0
  142. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/bytecode_compiler.cpp +0 -0
  143. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/bytecode_vm.cpp +0 -0
  144. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/colored_body.cpp +0 -0
  145. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/csg_generate.cpp +0 -0
  146. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/csg_resolve.cpp +0 -0
  147. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/css_colors.cpp +0 -0
  148. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/debug/debug_repl.cpp +0 -0
  149. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/debug_profile.cpp +0 -0
  150. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/eval_context.cpp +0 -0
  151. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/eval_error.cpp +0 -0
  152. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/eval_use.cpp +0 -0
  153. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/export.cpp +0 -0
  154. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/expr_eval.cpp +0 -0
  155. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/import/dxf_import.cpp +0 -0
  156. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/import/mesh_import.cpp +0 -0
  157. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/import/surface_load.cpp +0 -0
  158. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/import/svg_import.cpp +0 -0
  159. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/manifold_cache.cpp +0 -0
  160. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/stmt_eval.cpp +0 -0
  161. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/text/stb_font_provider.cpp +0 -0
  162. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/text/text_metrics.cpp +0 -0
  163. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/user_calls.cpp +0 -0
  164. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/value.cpp +0 -0
  165. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/src/zip_stored.cpp +0 -0
  166. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/CMakeLists.txt +0 -0
  167. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_booleans.cpp +0 -0
  168. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_bytecode_compiler.cpp +0 -0
  169. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_control_flow.cpp +0 -0
  170. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_csg_tree.cpp +0 -0
  171. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_debug_hooks.cpp +0 -0
  172. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_dxf_svg_import.cpp +0 -0
  173. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_eval_context.cpp +0 -0
  174. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_export.cpp +0 -0
  175. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_expr_eval.cpp +0 -0
  176. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_extrude_roof.cpp +0 -0
  177. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_function_builtins.cpp +0 -0
  178. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_helpers.hpp +0 -0
  179. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_manifold_cache.cpp +0 -0
  180. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_mesh_check.cpp +0 -0
  181. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_multi_color_merge.cpp +0 -0
  182. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_primitives.cpp +0 -0
  183. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_profiling.cpp +0 -0
  184. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_python_bindings.py +0 -0
  185. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_scope_trail.cpp +0 -0
  186. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_scoping.cpp +0 -0
  187. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_surface.cpp +0 -0
  188. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_tail_calls.cpp +0 -0
  189. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_text.cpp +0 -0
  190. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_transforms.cpp +0 -0
  191. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_unexpected_args.cpp +0 -0
  192. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_use.cpp +0 -0
  193. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_value.cpp +0 -0
  194. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_viewport_params.cpp +0 -0
  195. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tests/test_zip_stored.cpp +0 -0
  196. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tools/cli/CMakeLists.txt +0 -0
  197. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tools/cli/cli_lib.cpp +0 -0
  198. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tools/cli/cli_lib.hpp +0 -0
  199. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/tools/cli/main.cpp +0 -0
  200. {openscad_cpp_evaluator-0.31.0 → openscad_cpp_evaluator-0.31.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 0.31.0
3
+ Version: 0.31.2
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -51,7 +51,16 @@ struct MeshDiagnosis {
51
51
 
52
52
  // Diagnose `mesh` against all four conditions. Read-only; nothing is
53
53
  // modified and no exception is thrown for a broken mesh.
54
- MeshDiagnosis checkMesh(const manifold::MeshGL& mesh);
54
+ // Templated on the mesh type so callers can hand over MeshGL64 and keep
55
+ // their coordinates. This is not cosmetic: the welding below keys on a
56
+ // fixed 1e-6 grid, and float32's step exceeds that beyond coordinate
57
+ // magnitude ~17 -- so on any real model a float mesh is coarser than the
58
+ // tolerance these functions claim to work at, and genuinely distinct
59
+ // vertices collapse onto one key. Instantiated for MeshGL and MeshGL64.
60
+ template <typename M>
61
+ MeshDiagnosis checkMesh(const M& mesh);
62
+ extern template MeshDiagnosis checkMesh<manifold::MeshGL>(const manifold::MeshGL&);
63
+ extern template MeshDiagnosis checkMesh<manifold::MeshGL64>(const manifold::MeshGL64&);
55
64
 
56
65
  // What repairMesh did, for reporting. Not a diagnosis: these are actions.
57
66
  struct MeshRepairReport {
@@ -81,7 +90,10 @@ struct MeshRepairReport {
81
90
  //
82
91
  // Returns the repaired mesh. A mesh it cannot close is still returned,
83
92
  // improved as far as it got, with the remainder reported in `report`.
84
- manifold::MeshGL repairMesh(const manifold::MeshGL& mesh, MeshRepairReport& report);
93
+ template <typename M>
94
+ M repairMesh(const M& mesh, MeshRepairReport& report);
95
+ extern template manifold::MeshGL repairMesh<manifold::MeshGL>(const manifold::MeshGL&, MeshRepairReport&);
96
+ extern template manifold::MeshGL64 repairMesh<manifold::MeshGL64>(const manifold::MeshGL64&, MeshRepairReport&);
85
97
 
86
98
  struct SliverStripReport {
87
99
  size_t removed = 0; // zero-area faces taken out
@@ -103,6 +115,9 @@ struct SliverStripReport {
103
115
  // vertex restores the match without moving any geometry.
104
116
  //
105
117
  // The mesh is returned unchanged if it has no slivers.
106
- manifold::MeshGL stripSlivers(const manifold::MeshGL& mesh, SliverStripReport& report);
118
+ template <typename M>
119
+ M stripSlivers(const M& mesh, SliverStripReport& report);
120
+ extern template manifold::MeshGL stripSlivers<manifold::MeshGL>(const manifold::MeshGL&, SliverStripReport&);
121
+ extern template manifold::MeshGL64 stripSlivers<manifold::MeshGL64>(const manifold::MeshGL64&, SliverStripReport&);
107
122
 
108
123
  } // namespace oscadeval
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "0.31.0"
7
+ version = "0.31.2"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -267,19 +267,33 @@ std::vector<ColoredBody> generateImport(Evaluator& ev, const CSGParams& params,
267
267
  const auto& tris = std::get<ListPtr>(params.at("tris"))->items;
268
268
  if (tris.empty()) ev.error("import: mesh has no triangles", node);
269
269
 
270
- manifold::MeshGL mesh;
271
- mesh.numProp = 3;
270
+ // Kept at full precision for the Manifold that CSG will actually use --
271
+ // MeshGL is MeshGLP<float>, and truncating there does not merely lose
272
+ // digits, it snaps nearly-distinct coordinates onto exactly-equal ones
273
+ // and manufactures the degenerate coincidences that make a later
274
+ // boolean leave a zero-thickness membrane behind (see
275
+ // generatePolyhedron). STL carries only float32 to begin with, but
276
+ // OBJ/OFF/3MF are text and can hold more, and this is the same
277
+ // import() either way.
278
+ manifold::MeshGL64 mesh64;
279
+ mesh64.numProp = 3;
272
280
  for (const Value& v : std::get<ListPtr>(params.at("verts"))->items) {
273
- mesh.vertProperties.push_back(static_cast<float>(std::get<double>(v)));
281
+ mesh64.vertProperties.push_back(std::get<double>(v));
274
282
  }
275
- for (const Value& t : tris) mesh.triVerts.push_back(static_cast<uint32_t>(std::get<double>(t)));
283
+ for (const Value& t : tris) mesh64.triVerts.push_back(static_cast<uint64_t>(std::get<double>(t)));
284
+
285
+ // checkMesh/repairMesh work at this precision too, which matters here:
286
+ // they weld on a fixed 1e-6 grid, and float32's step is coarser than
287
+ // that beyond coordinate magnitude ~17, so a float mesh would have them
288
+ // merging vertices that are genuinely distinct on any real model.
289
+ manifold::MeshGL64& mesh = mesh64;
276
290
 
277
291
  const auto repairIt = params.find("repair");
278
292
  const bool repair = repairIt != params.end() && truthy(repairIt->second);
279
293
  if (repair) {
280
294
  const MeshDiagnosis before = checkMesh(mesh);
281
295
  MeshRepairReport rep;
282
- manifold::MeshGL fixed = repairMesh(mesh, rep);
296
+ manifold::MeshGL64 fixed = repairMesh(mesh, rep);
283
297
  const MeshDiagnosis after = checkMesh(fixed);
284
298
  if (rep.didAnything()) {
285
299
  ev.warn("import: repaired the mesh -- " + rep.summary(), &node.position());
@@ -308,7 +322,14 @@ std::vector<ColoredBody> generateImport(Evaluator& ev, const CSGParams& params,
308
322
  "); drawing it as a surface, but it cannot take part in any CSG "
309
323
  "operation" + (repair ? "" : ". Try import(..., repair=true)"),
310
324
  &node.position());
311
- return {ev.tagDisplayOnly(std::move(mesh), node, params.at("color"))};
325
+ // tagDisplayOnly carries a raw triangle soup for the renderer to
326
+ // draw, and the renderer is float either way, so narrowing here
327
+ // costs nothing this mesh will ever be measured on.
328
+ manifold::MeshGL soup;
329
+ soup.numProp = 3;
330
+ soup.vertProperties.assign(mesh.vertProperties.begin(), mesh.vertProperties.end());
331
+ soup.triVerts.assign(mesh.triVerts.begin(), mesh.triVerts.end());
332
+ return {ev.tagDisplayOnly(std::move(soup), node, params.at("color"))};
312
333
  }
313
334
  return {ev.tagGenerated(std::move(body), node, params.at("color"))};
314
335
  }
@@ -31,17 +31,21 @@ bool isUndef(const Value& v) { return std::holds_alternative<std::monostate>(v);
31
31
  // camera auto-fit to infinity, which is worse than showing nothing. The
32
32
  // explicit finite check is belt-and-braces, since nothing documents that a
33
33
  // NotManifold mesh can't ALSO contain a NaN.
34
- bool isDrawableFailure(const manifold::Manifold& body, const manifold::MeshGL& mesh) {
34
+ template <typename M>
35
+ bool isDrawableFailure(const manifold::Manifold& body, const M& mesh) {
35
36
  if (body.Status() != manifold::Manifold::Error::NotManifold) return false;
36
37
  if (mesh.triVerts.empty()) return false;
37
38
  return std::all_of(mesh.vertProperties.begin(), mesh.vertProperties.end(),
38
39
  [](float v) { return std::isfinite(v); });
39
40
  }
40
41
 
41
- size_t countBoundaryEdges(const manifold::MeshGL& mesh) {
42
+ template <typename M>
43
+ size_t countBoundaryEdges(const M& mesh) {
42
44
  std::map<std::pair<uint32_t, uint32_t>, int> uses;
43
45
  for (size_t i = 0; i + 2 < mesh.triVerts.size(); i += 3) {
44
- const uint32_t v[3] = {mesh.triVerts[i], mesh.triVerts[i + 1], mesh.triVerts[i + 2]};
46
+ const uint32_t v[3] = {static_cast<uint32_t>(mesh.triVerts[i]),
47
+ static_cast<uint32_t>(mesh.triVerts[i + 1]),
48
+ static_cast<uint32_t>(mesh.triVerts[i + 2])};
45
49
  for (int e = 0; e < 3; ++e) {
46
50
  const uint32_t a = v[e], b = v[(e + 1) % 3];
47
51
  ++uses[{std::min(a, b), std::max(a, b)}];
@@ -162,13 +166,13 @@ CSGParams resolveSphere(Evaluator& ev, const oscad::ModularCall& node, EvalConte
162
166
 
163
167
  std::vector<ColoredBody> generateSphere(Evaluator& ev, const CSGParams& params, const std::vector<std::unique_ptr<CSGNode>>&,
164
168
  const oscad::ASTNode& node) {
165
- manifold::MeshGL mesh;
169
+ manifold::MeshGL64 mesh;
166
170
  mesh.numProp = 3;
167
171
  for (const Value& v : std::get<ListPtr>(params.at("verts"))->items) {
168
- mesh.vertProperties.push_back(static_cast<float>(std::get<double>(v)));
172
+ mesh.vertProperties.push_back(std::get<double>(v));
169
173
  }
170
174
  for (const Value& t : std::get<ListPtr>(params.at("tris"))->items) {
171
- mesh.triVerts.push_back(static_cast<uint32_t>(std::get<double>(t)));
175
+ mesh.triVerts.push_back(static_cast<uint64_t>(std::get<double>(t)));
172
176
  }
173
177
  manifold::Manifold body(mesh);
174
178
  return {ev.tagGenerated(std::move(body), node, params.at("color"))};
@@ -473,13 +477,13 @@ CSGParams resolvePolyhedron(Evaluator& ev, const oscad::ModularCall& node, EvalC
473
477
 
474
478
  std::vector<ColoredBody> generatePolyhedron(Evaluator& ev, const CSGParams& params,
475
479
  const std::vector<std::unique_ptr<CSGNode>>&, const oscad::ASTNode& node) {
476
- manifold::MeshGL mesh;
480
+ manifold::MeshGL64 mesh;
477
481
  mesh.numProp = 3;
478
482
  for (const Value& v : std::get<ListPtr>(params.at("verts"))->items) {
479
- mesh.vertProperties.push_back(static_cast<float>(std::get<double>(v)));
483
+ mesh.vertProperties.push_back(std::get<double>(v));
480
484
  }
481
485
  for (const Value& t : std::get<ListPtr>(params.at("tris"))->items) {
482
- mesh.triVerts.push_back(static_cast<uint32_t>(std::get<double>(t)));
486
+ mesh.triVerts.push_back(static_cast<uint64_t>(std::get<double>(t)));
483
487
  }
484
488
  manifold::Manifold body(mesh);
485
489
  if (isDrawableFailure(body, mesh)) {
@@ -498,7 +502,11 @@ std::vector<ColoredBody> generatePolyhedron(Evaluator& ev, const CSGParams& para
498
502
  " boundary edge(s); drawing it as a surface, but it cannot "
499
503
  "take part in any CSG operation",
500
504
  &node.position());
501
- return {ev.tagDisplayOnly(std::move(mesh), node, params.at("color"))};
505
+ manifold::MeshGL soup;
506
+ soup.numProp = 3;
507
+ soup.vertProperties.assign(mesh.vertProperties.begin(), mesh.vertProperties.end());
508
+ soup.triVerts.assign(mesh.triVerts.begin(), mesh.triVerts.end());
509
+ return {ev.tagDisplayOnly(std::move(soup), node, params.at("color"))};
502
510
  }
503
511
  if (body.Status() != manifold::Manifold::Error::NoError) {
504
512
  // Broken vertex data rather than merely-open topology (a NaN
@@ -394,12 +394,18 @@ manifold::Manifold voronoiRoof(const manifold::CrossSection& cs, double fa, doub
394
394
  }
395
395
  }
396
396
 
397
- manifold::MeshGL mesh;
397
+ // MeshGL64, not MeshGL: MeshGL is MeshGLP<float>, so building through
398
+ // it truncates these coordinates to ~7 significant digits on the way
399
+ // into Manifold. That does not merely lose precision -- it snaps
400
+ // nearly-distinct coordinates onto exactly-equal ones, manufacturing
401
+ // the degenerate coincidences that make a later boolean leave a
402
+ // zero-thickness membrane behind. See generatePolyhedron.
403
+ manifold::MeshGL64 mesh;
398
404
  mesh.numProp = 3;
399
405
  for (const auto& v : verts) {
400
- mesh.vertProperties.push_back(static_cast<float>(v[0]));
401
- mesh.vertProperties.push_back(static_cast<float>(v[1]));
402
- mesh.vertProperties.push_back(static_cast<float>(v[2]));
406
+ mesh.vertProperties.push_back(v[0]);
407
+ mesh.vertProperties.push_back(v[1]);
408
+ mesh.vertProperties.push_back(v[2]);
403
409
  }
404
410
  for (const auto& t : tris) {
405
411
  mesh.triVerts.push_back(t[0]);
@@ -71,19 +71,21 @@ std::vector<ColoredBody> generateSurface(Evaluator& ev, const CSGParams& params,
71
71
  const auto top = [&](std::size_t r, std::size_t c) { return static_cast<uint32_t>(r * cols + c); };
72
72
  const auto bot = [&](std::size_t r, std::size_t c) { return static_cast<uint32_t>(n + r * cols + c); };
73
73
 
74
- manifold::MeshGL mesh;
74
+ // MeshGL64 -- see generatePolyhedron for why float truncation here
75
+ // manufactures degenerate coincidences for later booleans.
76
+ manifold::MeshGL64 mesh;
75
77
  mesh.numProp = 3;
76
78
  for (std::size_t r = 0; r < rows; ++r) {
77
79
  for (std::size_t c = 0; c < cols; ++c) {
78
- mesh.vertProperties.push_back(static_cast<float>(static_cast<double>(c) + xOff));
79
- mesh.vertProperties.push_back(static_cast<float>(static_cast<double>(r) + yOff));
80
- mesh.vertProperties.push_back(static_cast<float>(heights[r][c]));
80
+ mesh.vertProperties.push_back(static_cast<double>(c) + xOff);
81
+ mesh.vertProperties.push_back(static_cast<double>(r) + yOff);
82
+ mesh.vertProperties.push_back(heights[r][c]);
81
83
  }
82
84
  }
83
85
  for (std::size_t r = 0; r < rows; ++r) {
84
86
  for (std::size_t c = 0; c < cols; ++c) {
85
- mesh.vertProperties.push_back(static_cast<float>(static_cast<double>(c) + xOff));
86
- mesh.vertProperties.push_back(static_cast<float>(static_cast<double>(r) + yOff));
87
+ mesh.vertProperties.push_back(static_cast<double>(c) + xOff);
88
+ mesh.vertProperties.push_back(static_cast<double>(r) + yOff);
87
89
  mesh.vertProperties.push_back(0.0f);
88
90
  }
89
91
  }
@@ -15,29 +15,34 @@ using Edge = std::pair<Vert, Vert>;
15
15
 
16
16
  Edge undirected(Vert a, Vert b) { return {std::min(a, b), std::max(a, b)}; }
17
17
 
18
- size_t triCount(const manifold::MeshGL& m) { return m.triVerts.size() / 3; }
18
+ template <typename M>
19
+ size_t triCount(const M& m) { return m.triVerts.size() / 3; }
19
20
 
20
- void triVerts(const manifold::MeshGL& m, size_t t, Vert out[3]) {
21
+ template <typename M>
22
+ void triVerts(const M& m, size_t t, Vert out[3]) {
21
23
  out[0] = m.triVerts[t * 3];
22
24
  out[1] = m.triVerts[t * 3 + 1];
23
25
  out[2] = m.triVerts[t * 3 + 2];
24
26
  }
25
27
 
26
28
  // Position of vertex v, whatever the stride happens to be.
27
- void pos(const manifold::MeshGL& m, Vert v, double out[3]) {
29
+ template <typename M>
30
+ void pos(const M& m, Vert v, double out[3]) {
28
31
  const size_t stride = m.numProp ? m.numProp : 3;
29
32
  for (int i = 0; i < 3; ++i) out[i] = m.vertProperties[v * stride + i];
30
33
  }
31
34
 
32
35
  // A face naming the same vertex twice. Its "edges" include a self-edge, so
33
36
  // it cannot take part in the topology at all.
34
- bool repeatsAVertex(const manifold::MeshGL& m, size_t t) {
37
+ template <typename M>
38
+ bool repeatsAVertex(const M& m, size_t t) {
35
39
  Vert v[3];
36
40
  triVerts(m, t, v);
37
41
  return v[0] == v[1] || v[1] == v[2] || v[0] == v[2];
38
42
  }
39
43
 
40
- bool degenerate(const manifold::MeshGL& m, size_t t) {
44
+ template <typename M>
45
+ bool degenerate(const M& m, size_t t) {
41
46
  Vert v[3];
42
47
  triVerts(m, t, v);
43
48
  if (v[0] == v[1] || v[1] == v[2] || v[0] == v[2]) return true;
@@ -52,7 +57,8 @@ bool degenerate(const manifold::MeshGL& m, size_t t) {
52
57
 
53
58
  // Vertices that share a position but not an index. Keyed on rounded
54
59
  // coordinates, matching the welding polyhedron() already does.
55
- size_t countUnwelded(const manifold::MeshGL& m) {
60
+ template <typename M>
61
+ size_t countUnwelded(const M& m) {
56
62
  const size_t stride = m.numProp ? m.numProp : 3;
57
63
  const size_t n = stride ? m.vertProperties.size() / stride : 0;
58
64
  std::map<std::tuple<long long, long long, long long>, size_t> seen;
@@ -69,7 +75,8 @@ size_t countUnwelded(const manifold::MeshGL& m) {
69
75
  // The faces around `v`, as (prev, next) pairs on the opposite edge. The link
70
76
  // is one cycle when following those pairs from any starting corner visits
71
77
  // all of them; more than one walk means the surface pinches at v.
72
- size_t countPinched(const manifold::MeshGL& m,
78
+ template <typename M>
79
+ size_t countPinched(const M& m,
73
80
  const std::vector<std::vector<size_t>>& vertTris) {
74
81
  size_t pinched = 0;
75
82
  for (Vert v = 0; v < vertTris.size(); ++v) {
@@ -130,7 +137,8 @@ std::string MeshDiagnosis::summary() const {
130
137
  return out;
131
138
  }
132
139
 
133
- MeshDiagnosis checkMesh(const manifold::MeshGL& mesh) {
140
+ template <typename M>
141
+ MeshDiagnosis checkMesh(const M& mesh) {
134
142
  MeshDiagnosis d;
135
143
  const size_t tris = triCount(mesh);
136
144
  const size_t stride = mesh.numProp ? mesh.numProp : 3;
@@ -220,7 +228,8 @@ namespace {
220
228
  // Merge vertices that share a position. Everything downstream depends on
221
229
  // this: unwelded duplicates split one shared edge into two boundary edges,
222
230
  // so a mesh that is really closed reads as full of holes until it is done.
223
- std::vector<Vert> weldMap(const manifold::MeshGL& m, size_t& welded) {
231
+ template <typename M>
232
+ std::vector<Vert> weldMap(const M& m, size_t& welded) {
224
233
  const size_t stride = m.numProp ? m.numProp : 3;
225
234
  const size_t n = stride ? m.vertProperties.size() / stride : 0;
226
235
  std::map<std::tuple<long long, long long, long long>, Vert> first;
@@ -275,9 +284,10 @@ std::vector<std::vector<Vert>> boundaryLoops(const std::vector<std::array<Vert,
275
284
 
276
285
  } // namespace
277
286
 
278
- manifold::MeshGL repairMesh(const manifold::MeshGL& mesh, MeshRepairReport& report) {
287
+ template <typename M>
288
+ M repairMesh(const M& mesh, MeshRepairReport& report) {
279
289
  report = MeshRepairReport{};
280
- manifold::MeshGL out = mesh;
290
+ M out = mesh;
281
291
 
282
292
  // 1. Weld. Must come first -- it decides which edges are shared, and
283
293
  // every later step reads the edge map.
@@ -448,7 +458,8 @@ namespace {
448
458
  // between the same two points, so once it is gone the faces on either side
449
459
  // already meet along one edge and nothing needs splitting. The coincident
450
460
  // pair is merged so that is true by index as well as by position.
451
- bool coincidentPair(const manifold::MeshGL& m, const std::array<Vert, 3>& f,
461
+ template <typename M>
462
+ bool coincidentPair(const M& m, const std::array<Vert, 3>& f,
452
463
  Vert& keep, Vert& drop) {
453
464
  for (int i = 0; i < 3; ++i) {
454
465
  const Vert a = f[i], b = f[(i + 1) % 3];
@@ -468,7 +479,8 @@ bool coincidentPair(const manifold::MeshGL& m, const std::array<Vert, 3>& f,
468
479
 
469
480
  // Index of the vertex opposite the longest edge -- for three collinear
470
481
  // points that is the one in the middle.
471
- int middleOfCollinear(const manifold::MeshGL& m, const std::array<Vert, 3>& f) {
482
+ template <typename M>
483
+ int middleOfCollinear(const M& m, const std::array<Vert, 3>& f) {
472
484
  double p[3][3];
473
485
  for (int i = 0; i < 3; ++i) pos(m, f[i], p[i]);
474
486
  auto d2 = [&](int a, int b) {
@@ -484,7 +496,8 @@ int middleOfCollinear(const manifold::MeshGL& m, const std::array<Vert, 3>& f) {
484
496
 
485
497
  } // namespace
486
498
 
487
- manifold::MeshGL stripSlivers(const manifold::MeshGL& mesh, SliverStripReport& report) {
499
+ template <typename M>
500
+ M stripSlivers(const M& mesh, SliverStripReport& report) {
488
501
  report = SliverStripReport{};
489
502
  std::vector<std::array<Vert, 3>> tris;
490
503
  tris.reserve(triCount(mesh));
@@ -615,7 +628,7 @@ manifold::MeshGL stripSlivers(const manifold::MeshGL& mesh, SliverStripReport& r
615
628
  tris.swap(next);
616
629
  }
617
630
 
618
- manifold::MeshGL out = mesh;
631
+ M out = mesh;
619
632
  out.triVerts.clear();
620
633
  out.triVerts.reserve(tris.size() * 3);
621
634
  for (const auto& f : tris) {
@@ -631,4 +644,16 @@ manifold::MeshGL stripSlivers(const manifold::MeshGL& mesh, SliverStripReport& r
631
644
  return out;
632
645
  }
633
646
 
647
+
648
+ // Instantiated for both precisions: MeshGL for the paths that are float by
649
+ // nature (STL, the renderer), MeshGL64 wherever the caller still has its
650
+ // real coordinates. Keeping the definitions in this file, rather than the
651
+ // header, keeps compile times where they were.
652
+ template MeshDiagnosis checkMesh<manifold::MeshGL>(const manifold::MeshGL&);
653
+ template MeshDiagnosis checkMesh<manifold::MeshGL64>(const manifold::MeshGL64&);
654
+ template manifold::MeshGL repairMesh<manifold::MeshGL>(const manifold::MeshGL&, MeshRepairReport&);
655
+ template manifold::MeshGL64 repairMesh<manifold::MeshGL64>(const manifold::MeshGL64&, MeshRepairReport&);
656
+ template manifold::MeshGL stripSlivers<manifold::MeshGL>(const manifold::MeshGL&, SliverStripReport&);
657
+ template manifold::MeshGL64 stripSlivers<manifold::MeshGL64>(const manifold::MeshGL64&, SliverStripReport&);
658
+
634
659
  } // namespace oscadeval
@@ -11,6 +11,12 @@
11
11
  #include <cmath>
12
12
  #include <filesystem>
13
13
  #include <fstream>
14
+ #ifdef _WIN32
15
+ #include <process.h>
16
+ #define getpid _getpid
17
+ #else
18
+ #include <unistd.h>
19
+ #endif
14
20
  #include <gtest/gtest.h>
15
21
  #include <sstream>
16
22
 
@@ -33,8 +39,45 @@ const char* kAmbiguousNameScript = "function fib(n) = n < 2 ? n : fib(n-1) + fib
33
39
  "}\n"
34
40
  "thing(1);\n";
35
41
 
42
+ // One directory per process, created once.
43
+ //
44
+ // These tests write a script, run the CLI on it, and delete both it and
45
+ // their output again -- and they collide heavily on names: three share
46
+ // "m.scad" as input and twenty-four write "m_out.stl". Sharing one temp
47
+ // directory meant that under `ctest -j` a test would delete the script
48
+ // another was still reading (runCli then returns 1) or remove an output
49
+ // another had just written (exists(out) then fails). It looked like shared
50
+ // state in the debug REPL; it was only the filenames.
51
+ //
52
+ // The process id is what makes this work. ctest runs each discovered test
53
+ // as its OWN process, so a static counter or a hash of the script name is
54
+ // identical in every one of them -- an earlier attempt keyed on exactly
55
+ // that and changed nothing, because every process produced the same
56
+ // directory name. Names stay as they were, which matters: some tests
57
+ // assert on the filename the debugger prints ("m.scad:1").
58
+ const std::filesystem::path& testScratchDir() {
59
+ // Removed on the way out. The tests delete their own scripts and
60
+ // outputs, but the directory itself would otherwise pile up -- one per
61
+ // test process per run, which is 1,482 of them a suite.
62
+ struct Scratch {
63
+ std::filesystem::path path;
64
+ Scratch() {
65
+ path = std::filesystem::temp_directory_path() /
66
+ ("oscad_cli_test_" +
67
+ std::to_string(static_cast<unsigned long long>(::getpid())));
68
+ std::filesystem::create_directories(path);
69
+ }
70
+ ~Scratch() {
71
+ std::error_code ec;
72
+ std::filesystem::remove_all(path, ec); // best effort
73
+ }
74
+ };
75
+ static const Scratch scratch;
76
+ return scratch.path;
77
+ }
78
+
36
79
  std::filesystem::path writeScript(const std::string& name, const std::string& text) {
37
- const std::filesystem::path p = std::filesystem::temp_directory_path() / ("oscad_cli_test_" + name);
80
+ const std::filesystem::path p = testScratchDir() / name;
38
81
  std::ofstream out(p);
39
82
  out << text;
40
83
  return p;
@@ -308,3 +308,48 @@ TEST(ObjectBuiltin, PositionalMergesExistingObject) {
308
308
  const auto& items = std::get<ObjectPtr>(v)->items;
309
309
  ASSERT_EQ(items.size(), 3u);
310
310
  }
311
+
312
+ // -- mesh-built geometry keeps full precision ----------------------------
313
+ //
314
+ // polyhedron()/sphere()/roof()/surface()/import() build their Manifold from
315
+ // a mesh, and MeshGL is MeshGLP<float>. Going through it truncated script
316
+ // doubles to ~7 significant digits, which does not merely lose precision:
317
+ // it snaps nearly-distinct coordinates onto exactly-equal ones and
318
+ // manufactures degenerate coincidences that make a later boolean leave a
319
+ // zero-thickness membrane behind, sealing a hole that should go through.
320
+ //
321
+ // Found via a real user model (a coin-cell dispenser using BOSL2's
322
+ // rounded/teardrop cyl(), which builds through polyhedron()): the bore came
323
+ // out capped, the export was a valid closed solid a slicer would happily
324
+ // print solid, and every mesh integrity check passed -- watertight,
325
+ // manifold, orientable, no duplicate or degenerate faces. Only the genus
326
+ // gave it away. A plain cylinder() never showed it, because that is a
327
+ // Manifold primitive built in double precision all along.
328
+ // A whole-model reproduction needs BOSL2 (its rounded/teardrop cyl() is what
329
+ // builds through polyhedron() in the wild), which this suite cannot depend
330
+ // on -- and a hand-written box does NOT reproduce it: Manifold handles
331
+ // exactly-coincident PLANAR faces fine, as checked directly. The end-to-end
332
+ // case lives in BelfrySCAD's scratch/coplanar_cut_repro.scad. What is
333
+ // guarded here is the cause rather than one of its symptoms: that
334
+ // mesh-built geometry keeps the precision it was given.
335
+ TEST(MeshPrecision, PolyhedronKeepsCoordinatesFloatWouldRound) {
336
+ // 0.1 + 0.2 style values a float cannot hold: at float32 these two
337
+ // vertices would land on the same coordinate and the solid would
338
+ // degenerate. In doubles they stay apart.
339
+ Evaluated e = evalSrc(R"(
340
+ polyhedron(
341
+ points = [[0,0,0],[10.000000123,0,0],[10.000000123,10,0],[0,10,0],
342
+ [0,0,10],[10.000000123,0,10],[10.000000123,10,10],[0,10,10]],
343
+ faces = [[1,2,3,0],[7,6,5,4],[4,5,1,0],
344
+ [5,6,2,1],[6,7,3,2],[7,4,0,3]]);
345
+ )");
346
+ ASSERT_FALSE(e.bodies.empty());
347
+ const manifold::MeshGL64 mesh = e.bodies.front().body->GetMeshGL64();
348
+ double maxX = 0.0;
349
+ for (size_t i = 0; i < mesh.vertProperties.size(); i += mesh.numProp) {
350
+ maxX = std::max(maxX, mesh.vertProperties[i]);
351
+ }
352
+ // float32 would round this to 10.0 exactly; double keeps the tail.
353
+ EXPECT_GT(maxX, 10.0);
354
+ EXPECT_NEAR(maxX, 10.000000123, 1e-9);
355
+ }