openscad-cpp-evaluator 1.45.0__tar.gz → 1.45.1__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 (234) hide show
  1. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/PKG-INFO +1 -1
  2. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/pyproject.toml +1 -1
  3. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/roof.cpp +81 -20
  4. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_extrude_roof.cpp +79 -2
  5. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/uv.lock +1 -1
  6. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/.github/workflows/ci.yml +0 -0
  7. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/.github/workflows/wheels.yml +0 -0
  8. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/.gitignore +0 -0
  9. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/.gitmodules +0 -0
  10. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/CLAUDE.md +0 -0
  11. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/CMakeLists.txt +0 -0
  12. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/LICENSE +0 -0
  13. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/README.md +0 -0
  14. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/bindings/CMakeLists.txt +0 -0
  15. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/bindings/ast_to_py.cpp +0 -0
  16. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/bindings/module.cpp +0 -0
  17. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/cmake/embed_font.cmake +0 -0
  18. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/cmake/patch_manifold.cmake +0 -0
  19. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/examples/CMakeLists.txt +0 -0
  20. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/examples/eval_perf_benchmark.cpp +0 -0
  21. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/examples/manifold_cache_reuse.cpp +0 -0
  22. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/examples/minimal_debugger.cpp +0 -0
  23. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  24. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/.gitignore +0 -0
  25. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  26. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  27. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/LICENSE +0 -0
  28. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/README.md +0 -0
  29. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  30. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  31. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  32. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  33. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  34. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  35. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  36. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  37. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  38. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  39. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  40. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  41. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  42. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  43. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  44. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  45. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/.DS_Store +0 -0
  46. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  47. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/api.cpp +0 -0
  48. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  49. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  50. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  51. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  52. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  53. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  54. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  55. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  56. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  57. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  58. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  59. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  60. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  61. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  62. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  63. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  64. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/position.cpp +0 -0
  65. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  66. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  67. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  68. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  69. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  70. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  71. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  72. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  73. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  74. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
  75. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  76. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  77. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  78. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  79. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  80. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  81. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  82. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  83. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  84. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  85. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_profile_time.cpp +0 -0
  86. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  87. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  88. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  89. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  90. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  91. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
  92. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  93. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  94. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  95. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  96. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  97. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
  98. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  99. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  100. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  101. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  102. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
  103. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  104. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  105. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  106. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  107. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  108. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  109. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  110. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  111. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  112. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
  113. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/export.hpp +0 -0
  114. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  115. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  116. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  117. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  118. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  119. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  120. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  121. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  122. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  123. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  124. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  125. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  126. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  127. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  128. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  129. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  130. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/value.hpp +0 -0
  131. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  132. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/python/openscad_cpp_evaluator/__init__.py +0 -0
  133. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/resources/fonts/LICENSE +0 -0
  134. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/resources/fonts/LiberationSans-Bold.ttf +0 -0
  135. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
  136. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/resources/fonts/LiberationSans-Italic.ttf +0 -0
  137. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  138. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/CMakeLists.txt +0 -0
  139. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/booleans.cpp +0 -0
  140. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/builtins.hpp +0 -0
  141. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/call_args.cpp +0 -0
  142. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/color.cpp +0 -0
  143. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/control.cpp +0 -0
  144. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/dxf_dim.cpp +0 -0
  145. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/extrude.cpp +0 -0
  146. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/function_builtins.cpp +0 -0
  147. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/import.cpp +0 -0
  148. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/modifiers.cpp +0 -0
  149. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/primitives_2d.cpp +0 -0
  150. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/primitives_3d.cpp +0 -0
  151. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/profile_time.cpp +0 -0
  152. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/registry.cpp +0 -0
  153. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/segments.cpp +0 -0
  154. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/surface.cpp +0 -0
  155. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/text.cpp +0 -0
  156. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/topology.cpp +0 -0
  157. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/builtins/transforms.cpp +0 -0
  158. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/bytecode_compiler.cpp +0 -0
  159. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/bytecode_vm.cpp +0 -0
  160. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/colored_body.cpp +0 -0
  161. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/coverage.cpp +0 -0
  162. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/csg_generate.cpp +0 -0
  163. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/csg_resolve.cpp +0 -0
  164. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/css_colors.cpp +0 -0
  165. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/debug/debug_repl.cpp +0 -0
  166. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/debug_profile.cpp +0 -0
  167. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/eval_context.cpp +0 -0
  168. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/eval_error.cpp +0 -0
  169. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/eval_use.cpp +0 -0
  170. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/export.cpp +0 -0
  171. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/expr_eval.cpp +0 -0
  172. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/format_closure.cpp +0 -0
  173. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/import/dxf_import.cpp +0 -0
  174. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/import/mesh_import.cpp +0 -0
  175. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/import/scene_import.cpp +0 -0
  176. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/import/surface_load.cpp +0 -0
  177. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/import/svg_import.cpp +0 -0
  178. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/manifold_cache.cpp +0 -0
  179. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/measure_geometry.cpp +0 -0
  180. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/mesh_check.cpp +0 -0
  181. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/stmt_eval.cpp +0 -0
  182. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/text/font_match.cpp +0 -0
  183. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/text/freetype_font_provider.cpp +0 -0
  184. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/text/text_metrics.cpp +0 -0
  185. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/user_calls.cpp +0 -0
  186. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/utf8.cpp +0 -0
  187. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/value.cpp +0 -0
  188. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/xkcd_colors.cpp +0 -0
  189. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/xkcd_colors.hpp +0 -0
  190. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/src/zip_stored.cpp +0 -0
  191. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/CMakeLists.txt +0 -0
  192. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_booleans.cpp +0 -0
  193. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_bytecode_compiler.cpp +0 -0
  194. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_children_separate.cpp +0 -0
  195. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_cli.cpp +0 -0
  196. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_control_flow.cpp +0 -0
  197. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_coverage.cpp +0 -0
  198. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_csg_tree.cpp +0 -0
  199. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_debug_hooks.cpp +0 -0
  200. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_discretizer.cpp +0 -0
  201. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_dxf_svg_import.cpp +0 -0
  202. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_eval_context.cpp +0 -0
  203. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_export.cpp +0 -0
  204. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_expr_eval.cpp +0 -0
  205. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_feature_detection.cpp +0 -0
  206. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_function_builtins.cpp +0 -0
  207. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_helpers.hpp +0 -0
  208. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_import_export.cpp +0 -0
  209. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_include_cache.cpp +0 -0
  210. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_manifold_cache.cpp +0 -0
  211. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_mesh_check.cpp +0 -0
  212. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_multi_color_merge.cpp +0 -0
  213. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_openscad_parity.cpp +0 -0
  214. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_primitives.cpp +0 -0
  215. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_profile_time.cpp +0 -0
  216. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_profiling.cpp +0 -0
  217. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_python_bindings.py +0 -0
  218. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_render_expr.cpp +0 -0
  219. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_scope_trail.cpp +0 -0
  220. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_scoping.cpp +0 -0
  221. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_surface.cpp +0 -0
  222. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_tail_calls.cpp +0 -0
  223. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_text.cpp +0 -0
  224. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_transforms.cpp +0 -0
  225. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_undef_args.cpp +0 -0
  226. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_unexpected_args.cpp +0 -0
  227. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_use.cpp +0 -0
  228. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_value.cpp +0 -0
  229. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_viewport_params.cpp +0 -0
  230. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tests/test_zip_stored.cpp +0 -0
  231. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tools/cli/CMakeLists.txt +0 -0
  232. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tools/cli/cli_lib.cpp +0 -0
  233. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tools/cli/cli_lib.hpp +0 -0
  234. {openscad_cpp_evaluator-1.45.0 → openscad_cpp_evaluator-1.45.1}/tools/cli/main.cpp +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 1.45.0
3
+ Version: 1.45.1
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT AND OFL-1.1
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "1.45.0"
7
+ version = "1.45.1"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -114,10 +114,35 @@ class RoofMesh {
114
114
  }
115
115
  }
116
116
 
117
+ // A vertex no triangle uses -- the far end of an unbounded Voronoi edge
118
+ // outside the outline can lie 10^12 away -- would stretch the bounding
119
+ // box Manifold sizes its tolerance by, and its cleanup would then
120
+ // collapse the whole roof; such vertices are left out. (Only when one
121
+ // lies well beyond the rest: renumbering reorders the output, and one
122
+ // nearer changes the tolerance by no more than a few times.)
117
123
  manifold::Manifold build() {
118
124
  mesh_.numProp = 3;
125
+ const size_t n = mesh_.vertProperties.size() / 3;
126
+ std::vector<bool> used(n, false);
119
127
  for (const auto& t : triangles_) {
120
- for (int i : t) mesh_.triVerts.push_back(static_cast<uint64_t>(i));
128
+ for (int i : t) used[i] = true;
129
+ }
130
+ manifold::Box box;
131
+ for (size_t i = 0; i < n; ++i) {
132
+ if (used[i]) box.Union(manifold::vec3(mesh_.vertProperties[3 * i], mesh_.vertProperties[3 * i + 1], mesh_.vertProperties[3 * i + 2]));
133
+ }
134
+ std::vector<uint64_t> to(n);
135
+ std::vector<double> kept;
136
+ bool stray = false;
137
+ for (size_t i = 0; i < n; ++i) {
138
+ const manifold::vec3 p(mesh_.vertProperties[3 * i], mesh_.vertProperties[3 * i + 1], mesh_.vertProperties[3 * i + 2]);
139
+ stray = stray || (!used[i] && la::maxelem(la::abs(p)) > 16 * box.Scale());
140
+ to[i] = kept.size() / 3;
141
+ if (used[i]) kept.insert(kept.end(), {p.x, p.y, p.z});
142
+ }
143
+ if (stray) mesh_.vertProperties = std::move(kept);
144
+ for (const auto& t : triangles_) {
145
+ for (int i : t) mesh_.triVerts.push_back(stray ? to[i] : static_cast<uint64_t>(i));
121
146
  }
122
147
  manifold::Manifold body(mesh_);
123
148
  if (body.Status() == manifold::Manifold::Error::NoError) return body;
@@ -991,16 +1016,17 @@ void dropSpikes(std::vector<Vec2>& c) {
991
1016
  }
992
1017
  }
993
1018
 
994
- // The outline of `cs` snapped to a grid of 2^30 steps across its largest
995
- // coordinate, with repeated and straight corners dropped. Sets `toGrid`.
996
- std::vector<std::vector<Vec2>> gridContours(const manifold::CrossSection& cs, double& toGrid) {
1019
+ // The outline of `cs` snapped to a grid of 2^(bits+1) steps across its
1020
+ // largest coordinate, with repeated and straight corners dropped. Sets
1021
+ // `toGrid`.
1022
+ std::vector<std::vector<Vec2>> gridContours(const manifold::CrossSection& cs, double& toGrid, int bits = 29) {
997
1023
  const manifold::Polygons polys = cs.ToPolygons();
998
1024
  double extent = 0;
999
1025
  for (const auto& poly : polys) {
1000
1026
  for (Vec2 p : poly) extent = std::max({extent, std::abs(p.x), std::abs(p.y)});
1001
1027
  }
1002
1028
  if (!(extent > 0) || !std::isfinite(extent)) return {};
1003
- toGrid = std::ldexp(1.0, 29 - std::ilogb(extent));
1029
+ toGrid = std::ldexp(1.0, bits - std::ilogb(extent));
1004
1030
 
1005
1031
  std::vector<std::vector<Vec2>> contours;
1006
1032
  for (const auto& poly : polys) {
@@ -1016,17 +1042,6 @@ std::vector<std::vector<Vec2>> gridContours(const manifold::CrossSection& cs, do
1016
1042
  return contours;
1017
1043
  }
1018
1044
 
1019
- // The roof solid over `cs` (its floor at z = 0), discretizing curved parts
1020
- // by `fa`/`fs`.
1021
- manifold::Manifold voronoiRoof(const manifold::CrossSection& cs, double fa, double fs) {
1022
- double toGrid = 1;
1023
- std::vector<std::vector<Vec2>> contours = gridContours(cs, toGrid);
1024
- if (contours.empty()) return manifold::Manifold();
1025
- // $fa/$fs below 0.01 would ask for unbounded detail (computeRoofParams
1026
- // has already clamped them, warning).
1027
- return RoofBuilder(std::move(contours), 1 / toGrid, std::max(fa, 0.01), std::max(fs, 0.01)).build();
1028
- }
1029
-
1030
1045
  // The outline welded where it touches itself: a union can leave pieces
1031
1046
  // that share an edge, or a hole against the outline, as outlines a hairline
1032
1047
  // apart, crossing at nothing Clipper can see. Each corner within kWeld of
@@ -1062,8 +1077,11 @@ std::vector<std::vector<Vec2>> weldContours(std::vector<std::vector<Vec2>> conto
1062
1077
  }
1063
1078
  }
1064
1079
  }
1065
- // ponytail: every corner against every edge, O(n^2); a grid of edges
1066
- // when outlines of tens of thousands of corners matter.
1080
+ // Each edge looks only at the corners in its x range.
1081
+ // ponytail: still O(n^2) for an outline of long edges all spanning one
1082
+ // x range; a grid of edges if that ever matters.
1083
+ const auto byX = [](Vec2 p, Vec2 q) { return p.x != q.x ? p.x < q.x : p.y < q.y; };
1084
+ std::sort(corners.begin(), corners.end(), byX);
1067
1085
  Clipper2Lib::Paths64 paths;
1068
1086
  for (const auto& c : contours) {
1069
1087
  Clipper2Lib::Path64 path;
@@ -1074,8 +1092,10 @@ std::vector<std::vector<Vec2>> weldContours(std::vector<std::vector<Vec2>> conto
1074
1092
  if (len == 0) continue;
1075
1093
  const Vec2 lo = la::min(a, b) - kWeld, hi = la::max(a, b) + kWeld;
1076
1094
  std::vector<std::pair<double, Vec2>> on;
1077
- for (Vec2 q : corners) {
1078
- if (q.x < lo.x || q.y < lo.y || q.x > hi.x || q.y > hi.y || q == a || q == b) continue;
1095
+ for (auto it = std::lower_bound(corners.begin(), corners.end(), Vec2{lo.x, -std::numeric_limits<double>::infinity()}, byX);
1096
+ it != corners.end() && it->x <= hi.x; ++it) {
1097
+ const Vec2 q = *it;
1098
+ if (q.y < lo.y || q.y > hi.y || q == a || q == b) continue;
1079
1099
  const double t = la::dot(q - a, d) / len;
1080
1100
  if (t > 0 && t < len && std::abs(cross2(d, q - a)) / len <= kWeld) on.push_back({t, q});
1081
1101
  }
@@ -1095,6 +1115,47 @@ std::vector<std::vector<Vec2>> weldContours(std::vector<std::vector<Vec2>> conto
1095
1115
  return welded;
1096
1116
  }
1097
1117
 
1118
+ // Each contour rotated to start at its least corner, and the contours sorted:
1119
+ // equal for two outlines that differ only in where Clipper starts them.
1120
+ std::vector<std::vector<Vec2>> canonical(std::vector<std::vector<Vec2>> contours) {
1121
+ const auto less = [](Vec2 a, Vec2 b) { return a.x != b.x ? a.x < b.x : a.y < b.y; };
1122
+ for (auto& c : contours) std::rotate(c.begin(), std::min_element(c.begin(), c.end(), less), c.end());
1123
+ std::sort(contours.begin(), contours.end(), [&](const auto& a, const auto& b) { return std::lexicographical_compare(a.begin(), a.end(), b.begin(), b.end(), less); });
1124
+ return contours;
1125
+ }
1126
+
1127
+ // The roof solid over `cs` (its floor at z = 0), discretizing curved parts
1128
+ // by `fa`/`fs`.
1129
+ //
1130
+ // Boost's Voronoi builder needs segments that meet only at their ends. A
1131
+ // union's pieces sharing an edge come back as outlines a hairline apart,
1132
+ // which on the grid overlap or cross: the diagram comes out wrong, or the
1133
+ // builder never finishes, allocating without bound. So the outline is
1134
+ // welded first, as for the straight skeleton.
1135
+ //
1136
+ // Even on valid input the builder occasionally gets a near-degenerate
1137
+ // configuration wrong -- a cell left with no finite edges, where four sites
1138
+ // are all but equidistant once the outline is rounded to the grid -- and the
1139
+ // facets built from it do not close. Rounding to a coarser grid perturbs
1140
+ // the outline differently, so the roof is retried there.
1141
+ manifold::Manifold voronoiRoof(const manifold::CrossSection& cs, double fa, double fs) {
1142
+ manifold::Manifold body;
1143
+ for (int bits = 29; bits >= 25; --bits) {
1144
+ double toGrid = 1;
1145
+ std::vector<std::vector<Vec2>> contours = gridContours(cs, toGrid, bits);
1146
+ std::vector<std::vector<Vec2>> welded = weldContours(contours);
1147
+ // An outline welding leaves as it was keeps its own order, so its
1148
+ // roof is the same, vertex for vertex, as without welding.
1149
+ if (canonical(welded) != canonical(contours)) contours = std::move(welded);
1150
+ if (contours.empty()) return manifold::Manifold();
1151
+ // $fa/$fs below 0.01 would ask for unbounded detail
1152
+ // (computeRoofParams has already clamped them, warning).
1153
+ body = RoofBuilder(std::move(contours), 1 / toGrid, std::max(fa, 0.01), std::max(fs, 0.01)).build();
1154
+ if (body.Status() == manifold::Manifold::Error::NoError && !body.IsEmpty()) break;
1155
+ }
1156
+ return body;
1157
+ }
1158
+
1098
1159
  manifold::Manifold straightRoof(const manifold::CrossSection& cs) {
1099
1160
  double toGrid = 1;
1100
1161
  std::vector<std::vector<Vec2>> contours = weldContours(gridContours(cs, toGrid));
@@ -347,8 +347,8 @@ struct RoofResult {
347
347
  double slopeError; // roof area / (floor area * sqrt 2) - 1: 0 if every face rises at 45 degrees
348
348
  };
349
349
 
350
- RoofResult straightRoof(const std::string& shape) {
351
- Evaluated e = evalSrc("roof(method=\"straight\") " + shape);
350
+ RoofResult straightRoof(const std::string& shape, const std::string& method = "straight") {
351
+ Evaluated e = evalSrc("roof(method=\"" + method + "\") " + shape);
352
352
  EXPECT_EQ(e.bodies.size(), 1u);
353
353
  if (e.bodies.empty() || !e.bodies[0].body) return {0, 0, manifold::Manifold::Error::InvalidConstruction, 1};
354
354
  const manifold::Manifold& m = *e.bodies[0].body;
@@ -463,6 +463,83 @@ TEST(Roof, StraightHandlesThousandsOfVertices) {
463
463
  EXPECT_NEAR(g.slopeError, 0, 1e-5);
464
464
  }
465
465
 
466
+ // -- method="voronoi" over unions of pieces that touch along edges. These
467
+ // all gave no roof at all before: Clipper returns the pieces as outlines a
468
+ // hairline apart, which on the grid overlap or cross, and Boost's Voronoi
469
+ // builder needs segments that meet only at their ends.
470
+
471
+ namespace {
472
+
473
+ void expectVoronoiRoof(const std::string& shape, double volume, double height, double tol) {
474
+ SCOPED_TRACE(shape);
475
+ const RoofResult r = straightRoof(shape, "voronoi");
476
+ EXPECT_EQ(r.status, manifold::Manifold::Error::NoError);
477
+ EXPECT_NEAR(r.volume, volume, tol * volume);
478
+ EXPECT_NEAR(r.height, height, tol);
479
+ }
480
+
481
+ } // namespace
482
+
483
+ // Four triangles sharing edges. The reference agrees: 23.67785 / 2.39894.
484
+ TEST(Roof, VoronoiJoinsTrianglesThatShareEdges) {
485
+ expectVoronoiRoof("union() { polygon([[2.764760357, 4.118581106], [5.901400476, 6.372929785], [8.606126287, 1.988496895]]); "
486
+ "polygon([[5.901400476, 6.372929785], [8.606126287, 1.988496895], [11.028736411, 6.50946765]]); "
487
+ "polygon([[8.606126287, 1.988496895], [2.764760357, 4.118581106], [4.975336337, 1.106200614]]); "
488
+ "polygon([[8.606126287, 1.988496895], [2.764760357, 4.118581106], [6.985603416, 6.618989998]]); }",
489
+ 23.677855, 2.39894, 1e-5);
490
+ }
491
+
492
+ // Rotated rectangles sharing (parts of) edges. OpenSCAD 2026.02.01 draws
493
+ // nothing for it; the volume is the integral of the distance to the outline
494
+ // to within the faceting of the cones (170.68 numerically).
495
+ TEST(Roof, VoronoiJoinsRotatedRectanglesThatShareEdges) {
496
+ expectVoronoiRoof("union() { polygon([[-3.369828352, 0.413896268], [-7.46233132, 4.010047378], [-11.05848243, -0.08245559], [-6.965979462, -3.6786067]]); "
497
+ "polygon([[-4.919727978, -5.476682255], [-9.012230946, -1.880531145], [-14.406457611, -8.019285597], [-10.313954643, -11.615436707]]); "
498
+ "polygon([[6.613253139, -4.732154468], [0.474498687, 0.662072197], [-4.919727978, -5.476682255], [1.219026474, -10.87090892]]); "
499
+ "polygon([[10.457580178, -4.483978539], [8.411328694, -2.685902984], [6.613253139, -4.732154468], [8.659504623, -6.530230023]]); }",
500
+ 170.76468, 4.08601, 1e-5);
501
+ }
502
+
503
+ // Here the outline as Clipper leaves it crosses itself on the grid, and the
504
+ // Voronoi builder never finished, allocating until the process was killed
505
+ // (tens of gigabytes). (The integral of the distance to the outline is
506
+ // 221.3; the cones over corners meeting head on are faceted coarsely, as by
507
+ // the reference.)
508
+ TEST(Roof, VoronoiRoofOfACrossingOutlineStaysBounded) {
509
+ expectVoronoiRoof("union() { polygon([[8.304902057, -8.407695464], [0.596294574, -9.683488249], [1.872087359, -17.392095732], [9.580694842, -16.116302947]]); "
510
+ "polygon([[14.737716755, 0.576704804], [7.029109272, -0.699087981], [8.304902057, -8.407695464], [16.01350954, -7.131902679]]); "
511
+ "polygon([[8.304902057, -8.407695464], [-3.258009167, -10.321384641], [-2.620112775, -14.175688383], [8.94279845, -12.261999205]]); "
512
+ "polygon([[2.536909139, 2.517319368], [-1.317394603, 1.879422976], [0.596294574, -9.683488249], [4.450598316, -9.045591856]]); }",
513
+ 222.74776, 3.90673, 1e-5);
514
+ }
515
+
516
+ // A staircase of triangles. Outside it, two of its edges are all but
517
+ // parallel, so their Voronoi bisectors meet some 10^12 away; that vertex,
518
+ // used by no facet, stretched the bounding box Manifold sizes its tolerance
519
+ // by, and its cleanup collapsed the whole roof to nothing. (The integral of
520
+ // the distance to the outline is 78.02.)
521
+ TEST(Roof, VoronoiRoofIgnoresFarVoronoiVertices) {
522
+ expectVoronoiRoof("union() { polygon([[-1.015413575, -0.344245093], [-1.006343725, -5.505019653], [4.154430835, -5.495949802]]); "
523
+ "polygon([[-1.015413575, -0.344245093], [4.154430835, -5.495949802], [4.145360985, -0.335175242]]); "
524
+ "polygon([[-1.006343725, -5.505019653], [4.163500685, -10.656724363], [4.154430835, -5.495949802]]); "
525
+ "polygon([[4.154430835, -5.495949802], [4.163500685, -10.656724363], [9.324275246, -10.647654512]]); "
526
+ "polygon([[4.163500685, -10.656724363], [9.333345096, -15.808429072], [9.324275246, -10.647654512]]); "
527
+ "polygon([[-6.176188135, -0.353314943], [-1.006343725, -5.505019653], [-1.015413575, -0.344245093]]); }",
528
+ 78.047622, 3.02312, 1e-5);
529
+ }
530
+
531
+ // Axis-aligned rectangles: a clean outline, but rounded to the grid four
532
+ // sites are all but equidistant at one point, and Boost's builder leaves a
533
+ // cell with no finite edges. A coarser grid rounds it differently.
534
+ // OpenSCAD 2026.02.01 draws nothing here either; the integral of the
535
+ // distance to the outline is 1.348 (the faceted cone sits a little above).
536
+ TEST(Roof, VoronoiRetriesWhereTheBuilderFails) {
537
+ expectVoronoiRoof("union() { polygon([[0.7, -0.7], [2.1, -0.7], [2.1, 0.0], [0.7, 0.0]]); "
538
+ "polygon([[2.1, -0.7], [2.8, -0.7], [2.8, 0.7], [2.1, 0.7]]); "
539
+ "polygon([[2.8, -1.4], [4.2, -1.4], [4.2, 0.7], [2.8, 0.7]]); }",
540
+ 1.3513906, 0.820101, 1e-5);
541
+ }
542
+
466
543
  TEST(Roof, UnknownMethodWarnsAndFallsBackToVoronoi) {
467
544
  std::string lastWarning;
468
545
  Evaluated e = evalSrc("roof(method=\"bogus\") square(4, center=true);", [&](const std::string& msg) { lastWarning = msg; });
@@ -55,7 +55,7 @@ wheels = [
55
55
 
56
56
  [[package]]
57
57
  name = "openscad-cpp-evaluator"
58
- version = "1.45.0"
58
+ version = "1.45.1"
59
59
  source = { editable = "." }
60
60
  dependencies = [
61
61
  { name = "numpy" },