openscad-cpp-evaluator 1.42.0__tar.gz → 1.44.0__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 (245) hide show
  1. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/CLAUDE.md +60 -23
  2. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/PKG-INFO +3 -2
  3. openscad_cpp_evaluator-1.44.0/external/openscad_cpp_parser/LICENSE +21 -0
  4. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/bytecode.hpp +9 -16
  5. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -9
  6. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/colored_body.hpp +3 -3
  7. openscad_cpp_evaluator-1.44.0/include/openscad_cpp_evaluator/dxf_svg_import.hpp +67 -0
  8. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/evaluator.hpp +5 -0
  9. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/export.hpp +5 -8
  10. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/format_closure.hpp +4 -0
  11. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/import_builtin.hpp +3 -1
  12. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/segments.hpp +9 -18
  13. openscad_cpp_evaluator-1.44.0/include/openscad_cpp_evaluator/surface_load.hpp +20 -0
  14. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/value.hpp +3 -6
  15. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/pyproject.toml +3 -3
  16. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/CMakeLists.txt +1 -1
  17. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/booleans.cpp +2 -2
  18. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/builtins.hpp +20 -13
  19. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/control.cpp +2 -4
  20. openscad_cpp_evaluator-1.44.0/src/builtins/dxf_dim.cpp +220 -0
  21. openscad_cpp_evaluator-1.44.0/src/builtins/extrude.cpp +561 -0
  22. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/function_builtins.cpp +295 -395
  23. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/import.cpp +150 -80
  24. openscad_cpp_evaluator-1.44.0/src/builtins/primitives_2d.cpp +266 -0
  25. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/primitives_3d.cpp +122 -173
  26. openscad_cpp_evaluator-1.44.0/src/builtins/roof.cpp +1162 -0
  27. openscad_cpp_evaluator-1.44.0/src/builtins/segments.cpp +253 -0
  28. openscad_cpp_evaluator-1.44.0/src/builtins/surface.cpp +114 -0
  29. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/text.cpp +7 -1
  30. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/transforms.cpp +206 -190
  31. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/bytecode_compiler.cpp +2 -2
  32. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/bytecode_vm.cpp +4 -20
  33. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/colored_body.cpp +1 -1
  34. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/export.cpp +100 -46
  35. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/expr_eval.cpp +5 -6
  36. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/format_closure.cpp +2 -0
  37. openscad_cpp_evaluator-1.44.0/src/import/dxf_import.cpp +370 -0
  38. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/import/mesh_import.cpp +56 -18
  39. openscad_cpp_evaluator-1.44.0/src/import/surface_load.cpp +124 -0
  40. openscad_cpp_evaluator-1.44.0/src/import/svg_import.cpp +1017 -0
  41. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/stmt_eval.cpp +2 -1
  42. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/user_calls.cpp +11 -6
  43. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/value.cpp +140 -120
  44. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_bytecode_compiler.cpp +19 -19
  45. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_control_flow.cpp +3 -3
  46. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_csg_tree.cpp +2 -2
  47. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_dxf_svg_import.cpp +314 -51
  48. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_export.cpp +18 -5
  49. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_expr_eval.cpp +2 -2
  50. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_extrude_roof.cpp +153 -10
  51. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_helpers.hpp +24 -0
  52. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_import_export.cpp +56 -54
  53. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_openscad_parity.cpp +31 -0
  54. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_python_bindings.py +28 -2
  55. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_transforms.cpp +1 -0
  56. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_use.cpp +1 -1
  57. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_value.cpp +6 -7
  58. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/uv.lock +1 -1
  59. openscad_cpp_evaluator-1.42.0/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -46
  60. openscad_cpp_evaluator-1.42.0/include/openscad_cpp_evaluator/surface_load.hpp +0 -23
  61. openscad_cpp_evaluator-1.42.0/src/builtins/dxf_dim.cpp +0 -244
  62. openscad_cpp_evaluator-1.42.0/src/builtins/extrude.cpp +0 -549
  63. openscad_cpp_evaluator-1.42.0/src/builtins/primitives_2d.cpp +0 -242
  64. openscad_cpp_evaluator-1.42.0/src/builtins/roof.cpp +0 -489
  65. openscad_cpp_evaluator-1.42.0/src/builtins/segments.cpp +0 -284
  66. openscad_cpp_evaluator-1.42.0/src/builtins/surface.cpp +0 -118
  67. openscad_cpp_evaluator-1.42.0/src/import/dxf_import.cpp +0 -115
  68. openscad_cpp_evaluator-1.42.0/src/import/surface_load.cpp +0 -132
  69. openscad_cpp_evaluator-1.42.0/src/import/svg_import.cpp +0 -628
  70. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/.github/workflows/ci.yml +0 -0
  71. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/.github/workflows/wheels.yml +0 -0
  72. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/.gitignore +0 -0
  73. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/.gitmodules +0 -0
  74. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/CMakeLists.txt +0 -0
  75. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/LICENSE +0 -0
  76. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/README.md +0 -0
  77. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/bindings/CMakeLists.txt +0 -0
  78. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/bindings/ast_to_py.cpp +0 -0
  79. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/bindings/module.cpp +0 -0
  80. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/cmake/embed_font.cmake +0 -0
  81. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/cmake/patch_manifold.cmake +0 -0
  82. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/examples/CMakeLists.txt +0 -0
  83. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/examples/eval_perf_benchmark.cpp +0 -0
  84. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/examples/manifold_cache_reuse.cpp +0 -0
  85. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/examples/minimal_debugger.cpp +0 -0
  86. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  87. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/.gitignore +0 -0
  88. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  89. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  90. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/README.md +0 -0
  91. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  92. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  93. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  94. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  95. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  96. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  97. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  98. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  99. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  100. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  101. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  102. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  103. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  104. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  105. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  106. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  107. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/.DS_Store +0 -0
  108. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  109. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  110. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  111. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  112. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  113. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  114. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  115. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  116. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  117. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  118. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  119. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  120. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  121. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  122. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  123. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  124. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  125. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  126. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  127. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  128. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  129. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  130. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  131. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  132. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  133. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  134. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  135. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  136. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
  137. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  138. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  139. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  140. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  141. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  142. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  143. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  144. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  145. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  146. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  147. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_profile_time.cpp +0 -0
  148. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  149. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  150. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  151. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  152. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  153. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
  154. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  155. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  156. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  157. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  158. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  159. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  160. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  161. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
  162. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  163. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  164. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  165. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  166. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  167. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  168. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  169. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  170. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  171. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  172. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  173. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  174. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  175. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  176. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  177. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  178. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  179. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  180. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  181. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  182. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  183. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
  184. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/resources/fonts/LICENSE +0 -0
  185. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
  186. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
  187. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
  188. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  189. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/call_args.cpp +0 -0
  190. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/color.cpp +0 -0
  191. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/modifiers.cpp +0 -0
  192. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/profile_time.cpp +0 -0
  193. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/registry.cpp +0 -0
  194. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/builtins/topology.cpp +0 -0
  195. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/coverage.cpp +0 -0
  196. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/csg_generate.cpp +0 -0
  197. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/csg_resolve.cpp +0 -0
  198. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/css_colors.cpp +0 -0
  199. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/debug/debug_repl.cpp +0 -0
  200. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/debug_profile.cpp +0 -0
  201. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/eval_context.cpp +0 -0
  202. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/eval_error.cpp +0 -0
  203. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/eval_use.cpp +0 -0
  204. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/import/scene_import.cpp +0 -0
  205. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/manifold_cache.cpp +0 -0
  206. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/measure_geometry.cpp +0 -0
  207. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/mesh_check.cpp +0 -0
  208. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/text/font_match.cpp +0 -0
  209. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/text/freetype_font_provider.cpp +0 -0
  210. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/text/text_metrics.cpp +0 -0
  211. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/utf8.cpp +0 -0
  212. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/xkcd_colors.cpp +0 -0
  213. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/xkcd_colors.hpp +0 -0
  214. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/src/zip_stored.cpp +0 -0
  215. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/CMakeLists.txt +0 -0
  216. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_booleans.cpp +0 -0
  217. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_children_separate.cpp +0 -0
  218. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_cli.cpp +0 -0
  219. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_coverage.cpp +0 -0
  220. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_debug_hooks.cpp +0 -0
  221. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_discretizer.cpp +0 -0
  222. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_eval_context.cpp +0 -0
  223. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_feature_detection.cpp +0 -0
  224. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_function_builtins.cpp +0 -0
  225. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_include_cache.cpp +0 -0
  226. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_manifold_cache.cpp +0 -0
  227. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_mesh_check.cpp +0 -0
  228. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_multi_color_merge.cpp +0 -0
  229. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_primitives.cpp +0 -0
  230. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_profile_time.cpp +0 -0
  231. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_profiling.cpp +0 -0
  232. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_render_expr.cpp +0 -0
  233. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_scope_trail.cpp +0 -0
  234. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_scoping.cpp +0 -0
  235. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_surface.cpp +0 -0
  236. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_tail_calls.cpp +0 -0
  237. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_text.cpp +0 -0
  238. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_undef_args.cpp +0 -0
  239. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_unexpected_args.cpp +0 -0
  240. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_viewport_params.cpp +0 -0
  241. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tests/test_zip_stored.cpp +0 -0
  242. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tools/cli/CMakeLists.txt +0 -0
  243. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tools/cli/cli_lib.cpp +0 -0
  244. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tools/cli/cli_lib.hpp +0 -0
  245. {openscad_cpp_evaluator-1.42.0 → openscad_cpp_evaluator-1.44.0}/tools/cli/main.cpp +0 -0
@@ -63,7 +63,7 @@ plus gating the silent `is_undef` probe on the call actually resolving to the bu
63
63
  CSG-tree shape like union/difference/intersection, role-split via the shared `splitByRole`),
64
64
  `linear_extrude()`/`rotate_extrude()`/`projection(cut=)`, and `roof()`; and (Phase 7) `offset()`,
65
65
  `surface()` (`.dat` text + PNG/JPEG/BMP/GIF via `stb_image`), hand-rolled DXF (`LWPOLYLINE`/2D
66
- `POLYLINE`) and SVG (`path`/`polygon`/`polyline`/`rect`/`circle`/`ellipse`, nested
66
+ `POLYLINE`) and SVG (a port of upstream's libsvg: shapes, strokes, `<use>`, layers, nested
67
67
  `transform=`, all path commands including elliptical arcs) 2D contour import in both module
68
68
  (Region geometry) and expression (Region value) contexts, and the `FontProvider` abstraction
69
69
  (`font_provider.hpp`) + built-in FreeType/HarfBuzz backend + `text()`/`textmetrics()`/
@@ -211,8 +211,23 @@ Challenges and Experiences"), `roof.cpp` was rewritten from scratch as a close p
211
211
  `roof_vd.cc`'s `voronoi_diagram_roof`/`vd_inner_faces`/`discretize_arc` (CGAL/Eigen/Clipper2Lib
212
212
  swapped for `manifold::vec2` arithmetic and `manifold::Triangulate`), on top of Boost.Polygon's
213
213
  Voronoi builder (fetched as just `boostorg/polygon` + `boostorg/config`, confirmed to need nothing
214
- else from Boost). Both `method` values dispatch to this same construction (no CGAL-based `"straight"`
215
- path exists in this port). **Verified independently**, not just "it compiles": a brute-force
214
+ else from Boost). **`method="straight"` is its own construction** (`StraightSkeletonRoof` in
215
+ `roof.cpp`), a true straight-skeleton roof written from the literature (Aichholzer et al. 1995;
216
+ Felkel & Obdržálek 1998's event-driven wavefront) and the reference binary's black-box output --
217
+ no CGAL, and no OpenSCAD roof source read. It simulates the shrinking wavefront event by event
218
+ (edge, split and vertex events; a vertex event reconnects every wavefront edge at the meeting point
219
+ by angle), O(n^2 log n): 5000 vertices in ~0.5 s. Its input is welded first (`weldContours`: corners
220
+ within 2^-19 of the extent snapped together or onto edges, then a Clipper2 union), because a 2D
221
+ union often hands back pieces sharing an edge as separate outlines a hairline apart, and spikes
222
+ are cut away (`dropSpikes`). It matches OpenSCAD 2026.02.01 (`--enable=roof`) in volume, height and
223
+ vertex set on every shape compared that the reference does not crash on -- the reference segfaults
224
+ on many unions of rectangles/triangles that touch along edges, so those were checked only for being
225
+ valid 45-degree roofs (roof area = floor area x sqrt 2). Until this landed both methods built the
226
+ Voronoi roof, wrong for any concave outline. **Warnings**: `$fs`/`$fa` clamping (via the shared
227
+ `Discretizer::fromCtx`) and `Unknown roof method '...'` (a non-string shown as str() shows it) are
228
+ printed BEFORE the children run, as the reference does -- `computeRoofParams` therefore runs at
229
+ `Op::PushBuiltinWrap` time like every other wrap kind (it used to be deferred to Pop on the belief
230
+ that the warning followed the children). **Verified independently**, not just "it compiles": a brute-force
216
231
  distance-transform grid search over a square-frame-with-a-hole test case found the same ridge height
217
232
  (≈1.756) this implementation produces — the Python reference's own SDF fallback gets this case
218
233
  measurably wrong (≈1.5, ~15% low) since it was never more than a documented approximation for
@@ -1115,9 +1130,10 @@ grep for `ponytail:`.
1115
1130
  `toCrossSection`; no children/generate-time-bounds dependency, so its resolve/generate split is
1116
1131
  the simple kind (segment count for `r=` IS resolvable early here, unlike `rotate_extrude`'s,
1117
1132
  since `offset`'s own radius argument is already known at resolve time).
1118
- - `src/builtins/roof.cpp` — `roof()`, built on Boost.Polygon's segment Voronoi diagram (see the
1119
- `roof()` note above for the full story of why this replaced an earlier straight-skeleton
1120
- approximation mid-Phase-6). `voronoiRoof` scales the merged cross-section's polygons into signed
1133
+ - `src/builtins/roof.cpp` — `roof()`: the default `method="voronoi"` built on Boost.Polygon's
1134
+ segment Voronoi diagram (see the `roof()` note above for the full story of why this replaced an
1135
+ earlier straight-skeleton approximation mid-Phase-6), and `method="straight"`'s straight-skeleton
1136
+ wavefront simulation (`StraightSkeletonRoof`, same note). `voronoiRoof` scales the merged cross-section's polygons into signed
1121
1137
  32-bit integer coordinates (`chooseScale`, headroom below 2^31 for Boost.Polygon's own internal
1122
1138
  robustness margin), constructs the Voronoi diagram over the resulting segments, walks it
1123
1139
  (`vdInnerFaces`, discretizing parabolic point-vs-segment bisector edges via `discretizeArc`) to get
@@ -1248,9 +1264,13 @@ grep for `ponytail:`.
1248
1264
  the module *and* expression forms, enclosing transforms still apply to a selected element (it
1249
1265
  has to land where it does in the drawing), and **a filter that matches nothing imports nothing
1250
1266
  and warns** rather than falling back to the whole file — a cut layer that quietly became every
1251
- layer is the worst answer available. `layer=` stays DXF-only on purpose: upstream reuses the
1252
- name for SVG but reads only Inkscape's `inkscape:label`, a vendor convention rather than
1253
- anything SVG defines, so it cannot match a layer from any other tool. `id` had been in
1267
+ layer is the worst answer available. `layer=` (and deprecated `layername=`) also selects in
1268
+ SVG, as upstream does: an Inkscape layer (`inkscape:groupmode="layer"` with an
1269
+ `inkscape:label`). Alone it takes that layer's own group; with `id=`/`class=` it restricts them
1270
+ to elements inside the named layer at any depth. The selection rules were read off the binary:
1271
+ the nearest selected or `display:none` ancestor-or-self decides whether a shape is drawn, so an
1272
+ id selects an element even under a hidden layer, while `layer=` alone does not reach into a
1273
+ hidden sublayer. The miss warning names `id`, `layer`, `class` in that order. `id` had been in
1254
1274
  `registry.cpp`'s declared parameter list since long before anything read it, so a script
1255
1275
  filtering by id was accepted in full and silently handed the whole drawing.
1256
1276
  `resolveFilePath()` (also declared here, defined in import.cpp) — resolves a file argument
@@ -1281,20 +1301,37 @@ grep for `ponytail:`.
1281
1301
  triangle-count parity.
1282
1302
  - `include/openscad_cpp_evaluator/dxf_svg_import.hpp`, `src/import/dxf_import.cpp`,
1283
1303
  `src/import/svg_import.cpp` — hand-rolled, dependency-free 2D-contour loaders (no XML/DXF library
1284
- pulled in, matching the plan's §9 dependency table). `loadDxfContours()` reads DXF's group-code
1285
- text format directly (closed `LWPOLYLINE`/2D `POLYLINE` entities only, optional layer filter) --
1286
- covers the same narrow entity set the reference's own `ezdxf`-based loader does, nothing more.
1304
+ pulled in, matching the plan's §9 dependency table). `loadDxf()` reads DXF's group-code
1305
+ text format directly and matches OpenSCAD 2026.02.01's import, established black-box (its DXF
1306
+ source is GPL; do not read or port it): `LINE`/`CIRCLE`/`ARC`/`ELLIPSE`/`LWPOLYLINE`/`INSERT`
1307
+ become segments (arcs by the circle fragment rules), points snap to a 1/1024 grid, segments chain
1308
+ into paths that are ALL closed (an open chain gets a straight closing edge), filled even-odd;
1309
+ `origin=`/`scale=`/`layer=` and its warnings ("Illegal value", "Not enough input values",
1310
+ "Unsupported DXF Entity") as OpenSCAD has them. The notes atop `dxf_import.cpp` list the rules,
1311
+ the two ellipse bugs deliberately not copied, and the `POLYLINE` extension.
1287
1312
  `loadSvgContours()` pairs a minimal recursive-descent XML tree parser (open/close/self-closing
1288
- tags, quoted attributes, comments/CDATA/prolog skipping, entity decoding — no namespace URI
1289
- resolution, a tag's `prefix:` is stripped textually) with a close port of the reference's own
1290
- path-command tokenizer/flattener (`M`/`L`/`H`/`V`/`C`/`S`/`Q`/`T`/`A`, both absolute and relative,
1291
- cubic/quadratic Bezier flattening, full elliptical-arc endpoint-to-center parameterization) plus
1292
- `rect`/`circle`/`ellipse`/`polygon`/`polyline` and nested `transform="matrix()/translate()/
1293
- scale()/rotate()"` composition (including through `<g>` groups), in SVG user units at the
1294
- point-transform step, `applyMat()` (named to avoid colliding with `std::apply` in an ADL lookup
1295
- that broke the build once — see its own comment). **Placement is `pageMap()`, a port of the
1296
- reference's `import_svg.cc`**: the page's `width`/`height` to mm (a unitless length at `dpi=`,
1297
- 72 by default; `px` at 96), the `viewBox` scaled onto the page under `preserveAspectRatio`
1313
+ tags, quoted attributes, comments/CDATA/prolog skipping, entity and character-reference
1314
+ decoding, attribute whitespace normalisation; a tag keeps its `prefix:`, as libxml2 reports it,
1315
+ so `<svg:rect>` is not a rect -- in OpenSCAD either) with **a port of upstream's MIT-licensed
1316
+ `src/libsvg`** (its copyright notice is in the file): its `d` tokenizer with every quirk (a `-`
1317
+ is a token, `1.5.5` is two numbers, a number with trailing junk is 0), Beziers in `max($fn, 20)`
1318
+ segments, arcs and circles/ellipses through `Discretizer::circular` (circles at least 40),
1319
+ rounded `rect`s rebuilt as path data printed at 6 digits, `transform` with `skewX`/`skewY` and
1320
+ libsvg's argument-count checks, `<use>` of a shape in an earlier `<defs>` only, unknown
1321
+ elements (`<a>`, `<symbol>`, `<switch>`) see-through with their transform ignored, and
1322
+ **strokes**: an open subpath, `<line>` and `<polyline>` become their stroke's outline via
1323
+ Clipper2's `ClipperOffset` at 2^27 per user unit (measured), with `stroke-width` (below 0.01 is
1324
+ 1), `stroke-linecap` and `stroke-linejoin` (`bevel` maps to Clipper's Square, as libsvg has it).
1325
+ Each element then fills even-odd on its own and the elements union (`fill()`), which is what
1326
+ the reference does: separate overlapping rects union, one path's overlapping subpaths cancel.
1327
+ Two departures: an arc with a zero radius or coincident endpoints is a line or nothing, as the
1328
+ SVG spec says, where libsvg divides by zero and draws NaN vertices at the origin; and
1329
+ OpenSCAD's 2D pipeline drops vertices within ~1.1e-8 mm of collinear, which ours (any 2D
1330
+ shape, not just SVG) does not -- spec `paths-cubic02` keeps two such vertices at an S-curve's
1331
+ inflection. **Placement is `pageMap()`, matching the reference's `import_svg.cc` by its
1332
+ output**: the page's `width`/`height` to mm (a unitless length at `dpi=`,
1333
+ 72 by default; `px` at 96; a `dpi` below 0.001 warns and is 72), the `viewBox` scaled onto the
1334
+ page under `preserveAspectRatio`
1298
1335
  (default `xMidYMid meet`), and Y flipped about the page HEIGHT -- or about the drawing's centre
1299
1336
  with `center=true`. Negating Y alone, as this did before, put a unitless 100-unit drawing in 2.8x
1300
1337
  too large and below the X axis. Bounds match OpenSCAD 2026.02.01 (`SvgPlacement` tests).
@@ -1670,7 +1707,7 @@ the side-quad diagonal choice changes a twisted solid without changing its trian
1670
1707
  default below 3, so these are an extrude warped round Z. The warp inverts the solid for a positive
1671
1708
  angle, hence the mirror-in-Y dance.
1672
1709
  - Kept departure: `$fa`/`$fs` <= 0 fall back to 12/2 rather than upstream's clamp-to-0.01 with a warning.
1673
- - Not ported: `linear_extrude(v=)` (accepted, ignored); DXF/SVG import arcs don't read the discretizer.
1710
+ - Not ported: `linear_extrude(v=)` (accepted, ignored); DXF import arcs don't read the discretizer.
1674
1711
 
1675
1712
  ## Cancel and the module recursion limit (#554)
1676
1713
 
@@ -1,10 +1,11 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 1.42.0
3
+ Version: 1.44.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
- License-Expression: MIT
6
+ License-Expression: MIT AND OFL-1.1
7
7
  License-File: LICENSE
8
+ License-File: resources/fonts/LICENSE
8
9
  Classifier: Development Status :: 3 - Alpha
9
10
  Classifier: Intended Audience :: Developers
10
11
  Classifier: Operating System :: OS Independent
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-2026 BelfrySCAD Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -287,14 +287,13 @@ enum class Op {
287
287
  // this AFTER would silently drop uncacheable/ManifoldCache taint
288
288
  // tracking for a rands() call embedded in the wrapper's own
289
289
  // arguments), computes this site's own params for every kind except
290
- // Modifier (empty, no ctx push) and Roof (deferred to Pop -- see
291
- // BuiltinWrapSite's own doc comment) via that kind's own native
290
+ // Modifier (empty, no ctx push) via that kind's own native
292
291
  // compute function (computeTransformParams/computeColorParams/etc.,
293
292
  // builtins.hpp) -- always a possibly-$-scoped child EvalContext,
294
293
  // pushed onto f.ctxChain unconditionally for every non-Modifier kind
295
- // (Roof pushes it too, params or not) -- pushes a fresh ev.treeStack_
296
- // frame, and stashes {params, randsBefore, siteIdx, (Roof only)
297
- // deferredArgs} onto VmFrame::builtinWrapStack (a real per-frame LIFO
294
+ // -- pushes a fresh ev.treeStack_
295
+ // frame, and stashes {params, randsBefore, siteIdx} onto
296
+ // VmFrame::builtinWrapStack (a real per-frame LIFO
298
297
  // stack, not a single slot: Push/PopBuiltinWrap pairs can nest or
299
298
  // sequence within one frame's own instruction stream, e.g.
300
299
  // `translate(a) translate(b) recur();`). The compiler always emits a
@@ -311,12 +310,7 @@ enum class Op {
311
310
  // VmFrame::builtinWrapStack's own top entry FIRST (before anything
312
311
  // that can itself throw, e.g. Evaluator::setTreeDepthOrThrow below --
313
312
  // so the exception-teardown path's own pending count is already
314
- // correct if THIS throws); for Roof only, computes `pending.params`
315
- // HERE via computeRoofParams(ev, pending.deferredArgs, ctx) -- the one
316
- // kind whose params computation has an observable side effect
317
- // (ev.warn()) that must stay ordered AFTER children, unlike every
318
- // other kind's params (computed at Push, before children, since
319
- // nothing else in this group has an order-sensitive side effect); pops
313
+ // correct if THIS throws); pops
320
314
  // the ctx Push made (every kind except Modifier); pops ev.treeStack_
321
315
  // to retrieve the children this bracket's own body produced, and
322
316
  // builds the tagged CSGNode exactly like Evaluator::buildTreeNode's
@@ -956,10 +950,9 @@ struct CompiledChunk {
956
950
  // rotate_extrude()/projection()/offset()/roof()) share Transform/
957
951
  // Color's exact push-time-computed-params shape, just via a different
958
952
  // native compute function each (Op::PushBuiltinWrap's own runtime
959
- // handler switches on `kind` to pick it) -- see that op's own doc
960
- // comment for the one exception (Roof, whose params computation has
961
- // to run at POP time instead, after children, to preserve an
962
- // observable warn() ordering).
953
+ // handler switches on `kind` to pick it). Roof's warnings ($fs/$fa
954
+ // clamping, unknown method) therefore come before its children's
955
+ // output, as in OpenSCAD 2026.02.01.
963
956
  struct BuiltinWrapSite {
964
957
  enum class Kind {
965
958
  Transform,
@@ -977,7 +970,7 @@ struct CompiledChunk {
977
970
  RotateExtrude,
978
971
  Projection,
979
972
  Offset,
980
- Roof, // computed at POP time, not PUSH -- see this struct's own doc comment
973
+ Roof,
981
974
  };
982
975
  Kind kind;
983
976
  std::string tagName; // "translate"/"rotate"/.../"color"/"highlight"/"background"/"show_only"/"hull"/...
@@ -30,15 +30,6 @@ struct PendingBuiltinWrap {
30
30
  CSGParams params;
31
31
  std::uint64_t randsBefore = 0;
32
32
  int siteIdx = -1;
33
- // Only populated for BuiltinWrapSite::Kind::Roof -- the already-
34
- // resolved call arguments, retained across the whole bracket so
35
- // Op::PopBuiltinWrap's handler can compute roof()'s own params AFTER
36
- // children finish (computeRoofParams needs them; re-running
37
- // resolveCallArgs at Pop time instead would re-evaluate every argument
38
- // expression a second time -- double rands()/side effects). Every
39
- // other kind computes its params at Push time and leaves this default-
40
- // empty.
41
- CallArgs deferredArgs;
42
33
 
43
34
  // ev.measuring_ as it stood immediately BEFORE this bracket opened.
44
35
  // Recorded for EVERY kind, not just Measure, so the exception teardown
@@ -188,7 +188,7 @@ std::vector<ColoredBody> toRenderableBodies(const std::vector<ColoredBody>& bodi
188
188
  double flatHeight = kTopLevel2dHeight);
189
189
 
190
190
  // A 3D affine transform as it acts on the XY plane: rows x and y, columns
191
- // x, y and translation -- what OpenSCAD's GeometryEvaluator applies to 2D
191
+ // x, y and translation -- what OpenSCAD applies to 2D
192
192
  // geometry (z, and everything out of the plane, simply drops away).
193
193
  manifold::mat2x3 projectTo2d(const manifold::mat3x4& m);
194
194
 
@@ -203,10 +203,10 @@ bool projectSectionXform(ColoredBody& b);
203
203
 
204
204
  // Applies `m`, projected onto the plane, to a CrossSection. A singular
205
205
  // projection -- scale([0,1]), a quarter turn about X -- empties it, as
206
- // upstream's Polygon2d::transform does, and returns false.
206
+ // OpenSCAD does, and returns false.
207
207
  bool transformSection(manifold::CrossSection& cs, const manifold::mat3x4& m);
208
208
 
209
- // Upstream's warning for that case, word for word.
209
+ // OpenSCAD's warning for that case, word for word.
210
210
  inline constexpr const char* kZeroScale2dWarning = "Scaling a 2D object with 0 - removing object";
211
211
 
212
212
  } // namespace oscadeval
@@ -0,0 +1,67 @@
1
+ #pragma once
2
+
3
+ #include "openscad_cpp_evaluator/segments.hpp"
4
+
5
+ #include <array>
6
+ #include <optional>
7
+ #include <string>
8
+ #include <vector>
9
+
10
+ namespace oscadeval {
11
+
12
+ using Contour2d = std::vector<std::array<double, 2>>;
13
+
14
+ // import()'s DXF arguments. `disc` carries $fn/$fa/$fs/$fe for arcs.
15
+ struct DxfOptions {
16
+ std::optional<std::string> layer;
17
+ double xorigin = 0.0, yorigin = 0.0, scale = 1.0;
18
+ Discretizer disc;
19
+ };
20
+
21
+ // The outlines, to be filled even-odd, and OpenSCAD's warnings about the
22
+ // file, in the order it prints them.
23
+ struct DxfImport {
24
+ std::vector<Contour2d> contours;
25
+ std::vector<std::string> warnings;
26
+ };
27
+
28
+ // Hand-rolled DXF reader matching OpenSCAD 2026.02.01's import (see the
29
+ // notes atop dxf_import.cpp): LINE, CIRCLE, ARC, ELLIPSE, LWPOLYLINE,
30
+ // POLYLINE and INSERT, chained into closed outlines. Throws
31
+ // std::runtime_error on I/O failure.
32
+ DxfImport loadDxf(const std::string& path, const DxfOptions& opts = {});
33
+
34
+ // SVG reader, as OpenSCAD 2026.02.01 reads it (a port of its MIT-licensed
35
+ // libsvg): <path>, <rect>, <circle>, <ellipse>, <line>, <polygon>,
36
+ // <polyline> and <use>, with transforms, display:none, and strokes -- an
37
+ // open path, <line> or <polyline> is drawn as its stroke's outline. Curves
38
+ // split by `disc`. Y is flipped (SVG's is down, OpenSCAD's is up). Throws
39
+ // std::runtime_error on I/O/parse failure.
40
+ //: Which part of the drawing to import. All unset means the whole file.
41
+ //: `id` matches an element's `id` attribute; `cls` (not an OpenSCAD
42
+ //: parameter) one entry of its space-separated `class` list; either takes
43
+ //: everything under the element, so naming a <g> means "that group".
44
+ //: `layer` names an Inkscape layer (inkscape:groupmode="layer", by its
45
+ //: inkscape:label): alone it takes that layer, with id/cls it restricts
46
+ //: them to elements inside it.
47
+ struct SvgFilter {
48
+ std::optional<std::string> id;
49
+ std::optional<std::string> cls;
50
+ std::optional<std::string> layer;
51
+ };
52
+
53
+ // `matched`, when given, reports whether the filter found anything. A miss
54
+ // imports nothing rather than falling back to the whole drawing; the caller
55
+ // warns. Always true when no filter was set.
56
+ // Placed as OpenSCAD places them: page units to mm (a unitless length at
57
+ // `dpi`), the viewBox under preserveAspectRatio, Y flipped about the page
58
+ // height -- or about the drawing's centre with `center`. The result is
59
+ // filled: overlapping contours have already been combined.
60
+ std::vector<Contour2d> loadSvgContours(const std::string& path,
61
+ const SvgFilter& filter = {},
62
+ bool* matched = nullptr,
63
+ double dpi = 72.0,
64
+ bool center = false,
65
+ const Discretizer& disc = {});
66
+
67
+ } // namespace oscadeval
@@ -587,6 +587,11 @@ public:
587
587
  // warnCapture first when one is active. Every warning path goes through
588
588
  // here, including a ManifoldCache hit replaying a cached line.
589
589
  void emitWarning(const std::string& formatted);
590
+ // "ERROR: {message}{locSuffix(position)}" that does NOT stop the run:
591
+ // OpenSCAD logs several of its errors this way and carries on.
592
+ void nonFatalError(const std::string& message, const oscad::Position* position) {
593
+ emitWarning("ERROR: " + message + locSuffix(position));
594
+ }
590
595
 
591
596
  // Applies OpenSCAD's mixed-2D/3D rules to a node's children just
592
597
  // before its GenerateFn runs -- see csg_generate.cpp.
@@ -167,7 +167,7 @@ struct ExportSvgOptions {
167
167
  void writeSvg(const std::string& path, const std::vector<ColoredBody>& bodies,
168
168
  const ExportSvgOptions& opts = {});
169
169
 
170
- // DXF, the third 2D writer: OpenSCAD's own export_dxf.cc layout (an AC1006
170
+ // DXF, the third 2D writer: byte-compatible with OpenSCAD's layout (an AC1006
171
171
  // header with the model's extents, one CONTINUOUS linetype, layer 0) and
172
172
  // every contour of every body a closed LWPOLYLINE on layer 0 -- holes are
173
173
  // contours like any other, as in OpenSCAD. A 1-vertex contour is a POINT
@@ -259,13 +259,10 @@ struct ExportPovOptions {
259
259
  // POV-Ray scene description. Every object splitBodiesForExport produces is
260
260
  // one mesh2 -- a welded vertex list, a texture per colour, and a texture
261
261
  // index per triangle, so per-triangle colour needs no unwelding -- with
262
- // inside_vector, which makes it a SOLID to POV-Ray (refraction, CSG). That
263
- // is the difference from OpenSCAD's export_pov.cc, which writes every face
264
- // as its own flat polygon object. The rest of the scene is OpenSCAD's: its
265
- // header, MATERIAL finish and ior 1.32 interior, 27 lights around the
266
- // bounding box, its camera, and radiosity from rad_def.inc. Colour is rgbf
267
- // with filter = 1 - alpha, as OpenSCAD writes it. Numbers are the shortest
268
- // text that round-trips, in the classic locale.
262
+ // inside_vector, which makes it a SOLID to POV-Ray (refraction, CSG). The
263
+ // rest of the scene (material, lights, default camera) is spec section F2.
264
+ // Colour is rgbf with filter = 1 - alpha. Numbers are the shortest text that
265
+ // round-trips, in the classic locale.
269
266
  void writePov(const std::string& path, const std::vector<ExportObject>& objects,
270
267
  const ExportPovOptions& opts = {});
271
268
 
@@ -3,6 +3,7 @@
3
3
  #include <string>
4
4
 
5
5
  namespace oscad {
6
+ class ASTNode;
6
7
  class FunctionLiteral;
7
8
  }
8
9
 
@@ -16,5 +17,8 @@ namespace oscadeval {
16
17
  // precedence-minimal and which 94 places inside the parser depend on. See
17
18
  // format_closure.cpp for where each rule came from.
18
19
  std::string formatFunctionLiteral(const oscad::FunctionLiteral& fn);
20
+ // Any expression, spelled the same way: what assert() quotes as its
21
+ // condition ("Assertion '(a > 1)' failed").
22
+ std::string formatExpression(const oscad::ASTNode& expr);
19
23
 
20
24
  } // namespace oscadeval
@@ -9,12 +9,14 @@ class ASTNode;
9
9
  namespace oscadeval {
10
10
 
11
11
  class Evaluator;
12
+ struct EvalContext;
12
13
 
13
14
  // import() used as an expression (not a geometry statement): returns a VNF
14
15
  // ([[verts],[faces]]) for a mesh file (.stl/.obj/.off/.3mf), or the JSON
15
16
  // file's content converted to native values (.json). DXF/SVG-as-Region
16
17
  // import lands alongside their module-context counterparts in a later
17
18
  // phase. Mirrors Evaluator._import_as_value (minus the dxf/svg branch).
18
- Value importAsValue(Evaluator& ev, const CallArgs& args, const oscad::ASTNode& node);
19
+ // `ctx` supplies $fn/$fa/$fs/$fe for an SVG's curves.
20
+ Value importAsValue(Evaluator& ev, const CallArgs& args, const oscad::ASTNode& node, const EvalContext& ctx);
19
21
 
20
22
  } // namespace oscadeval
@@ -11,34 +11,25 @@
11
11
 
12
12
  namespace oscadeval {
13
13
 
14
- // How curves become polygons: OpenSCAD's CurveDiscretizer (src/core/
15
- // CurveDiscretizer.cc, upstream master cc19000e0), ported. Every count here
16
- // matches the 2026.02.01 binary's.
17
- //
18
- // $fn > $fe > $fa/$fs. $fe is the most a curve's polygon may stray from the
19
- // true circle, measured along a radius to an edge's midpoint; when set (>=
20
- // 2^-20) it replaces $fa/$fs entirely. Upstream reads $fe only behind
21
- // --enable=discretization-by-error; this evaluator always honours it, and
22
- // advertises that as supported_feature("discretization-by-error").
23
- //
24
- // Departures from upstream, kept from before this port: $fa/$fs <= 0 fall
25
- // back to their defaults (12/2) rather than clamping to 0.01 with a warning.
14
+ // How curves become polygons: segment and slice counts from $fn/$fe/$fa/$fs
15
+ // (spec sections B7 and C6). $fe is always honoured here (OpenSCAD reads it
16
+ // only behind --enable=discretization-by-error), advertised as
17
+ // supported_feature("discretization-by-error").
26
18
  struct Discretizer {
27
19
  double fn = 0.0;
28
20
  double fe = 0.0;
29
21
  double fa = 12.0;
30
22
  double fs = 2.0;
31
23
 
32
- // `warn`, when given, receives upstream's clamping warnings.
24
+ // `warn`, when given, receives the clamping warnings (spec section B7).
33
25
  static Discretizer fromCtx(const EvalContext& ctx, const std::function<void(const std::string&)>& warn = {});
34
26
  // Stored in, and read back from, a node's params -- they are part of its
35
27
  // cache key, and generate has only the params to go on.
36
28
  static Discretizer fromParams(const CSGParams& params);
37
29
  void store(CSGParams& params) const;
38
30
 
39
- // Segments for `angle` degrees of arc at radius r. nullopt where
40
- // upstream has none (r below 2^-20, a non-finite $fn/$fe/angle): every
41
- // caller supplies its own fallback, as upstream's value_or() does.
31
+ // Segments for `angle` degrees of arc at radius r. nullopt where there is
32
+ // no count (spec section B7); every caller supplies its own fallback.
42
33
  std::optional<int> circular(double r, double angleDegrees = 360.0) const;
43
34
 
44
35
  // linear_extrude slice counts: twist without scale, twist with uniform
@@ -54,8 +45,8 @@ struct Discretizer {
54
45
  double scaleX, double scaleY, unsigned slices, unsigned segments) const;
55
46
  };
56
47
 
57
- // Full-circle segment count from ctx's $fn/$fe/$fa/$fs at radius r;
58
- // upstream's primitives fall back to 3.
48
+ // Full-circle segment count from ctx's $fn/$fe/$fa/$fs at radius r, or 3
49
+ // when there is none.
59
50
  int fnSegmentsFromCtx(const EvalContext& ctx, double r = 0.0,
60
51
  const std::function<void(const std::string&)>& warn = {});
61
52
 
@@ -0,0 +1,20 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+ #include <vector>
5
+
6
+ namespace oscadeval {
7
+
8
+ // Height data for surface() (spec section D3). Never throws: a file that
9
+ // cannot be read gives no heights and a warning, and the script carries on.
10
+ // `heights[row * cols + col]`; `minVal` is what the base sits 1 below.
11
+ struct SurfaceData {
12
+ std::vector<double> heights;
13
+ int rows = 0;
14
+ int cols = 0;
15
+ double minVal = 0;
16
+ std::vector<std::string> warnings;
17
+ };
18
+ SurfaceData loadSurface(const std::string& path, bool invert);
19
+
20
+ } // namespace oscadeval
@@ -268,12 +268,9 @@ Value vecSub(const Value& a, const Value& b);
268
268
  // behavior in the reference implementation -- revisit only if a real
269
269
  // script's `*` on a bool-containing vector is shown to need it.
270
270
  //
271
- // `error`, when non-null, receives the reference's own diagnostic text for
272
- // whichever undefined case was hit (multiply_visitor / multvecvec /
273
- // multmatvec / multvecmat in the reference's Value.cc) -- "vector*vector
274
- // requires matching lengths (2 != 3)", "Matrix must be rectangular. Problem
275
- // at row 1", and so on. applyBinaryOp warns with it; a caller that only
276
- // wants the value can leave it null. It is only written on an undef result.
271
+ // `error`, when non-null, receives the diagnostic for whichever undefined
272
+ // case was hit (spec section A6); applyBinaryOp warns with it. It is only
273
+ // written on an undef result.
277
274
  Value matmul(const Value& a, const Value& b, std::string* error = nullptr);
278
275
 
279
276
  // OpenSCAD's echo()/str() number formatting: at most 6 significant digits,
@@ -4,12 +4,12 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "1.42.0"
7
+ version = "1.44.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
11
- license = "MIT"
12
- license-files = ["LICENSE"]
11
+ license = "MIT AND OFL-1.1"
12
+ license-files = ["LICENSE", "resources/fonts/LICENSE"]
13
13
  authors = [{ name = "NeuSCAD Contributors" }]
14
14
  classifiers = [
15
15
  "Development Status :: 3 - Alpha",
@@ -68,7 +68,7 @@ target_include_directories(openscad_cpp_evaluator PRIVATE ${stb_SOURCE_DIR} ${CM
68
68
  add_dependencies(openscad_cpp_evaluator generate_bundled_font)
69
69
 
70
70
  target_link_libraries(openscad_cpp_evaluator PUBLIC openscad_cpp_parser manifold Boost::polygon)
71
- target_link_libraries(openscad_cpp_evaluator PRIVATE linenoise freetype harfbuzz)
71
+ target_link_libraries(openscad_cpp_evaluator PRIVATE linenoise freetype harfbuzz Clipper2)
72
72
  target_compile_options(openscad_cpp_evaluator PRIVATE
73
73
  $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall;-Wextra>
74
74
  )
@@ -392,8 +392,8 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
392
392
  }
393
393
 
394
394
  RoleSplit split = splitByRole(stmtBodies);
395
- // A `%` statement is scenery, not an operand: upstream leaves it out
396
- // of the CSG entirely (collectChildren skips isBackground()), so the
395
+ // A `%` statement is scenery, not an operand: OpenSCAD leaves it out
396
+ // of the CSG entirely, so the
397
397
  // NEXT statement is the minuend of a difference(), and an
398
398
  // intersection() is not cancelled by it. It was taken as an empty
399
399
  // operand, which emptied both. Only the `%` statement itself: a
@@ -246,17 +246,11 @@ CSGParams resolveOffset(Evaluator& ev, const oscad::ModularCall& node, EvalConte
246
246
  std::vector<ColoredBody> generateOffset(Evaluator& ev, const CSGParams& params,
247
247
  const std::vector<std::unique_ptr<CSGNode>>& children, const oscad::ASTNode& node);
248
248
 
249
- // roof() -- roof.cpp. Tier 1 (exact straight skeleton, stable single-
250
- // contour polygons) + Tier 3 (SDF/level-set fallback) only, per the plan --
251
- // Tier 2 (general multi-contour/hole straight skeleton) is a named,
252
- // documented follow-up, not silently dropped (see CLAUDE.md).
253
- // computeRoofParams: UNLIKE computeLinearExtrudeParams and friends above,
254
- // this is the params-computation half taken from AFTER evalChildren (it
255
- // calls ev.warn(), an observable side effect that must stay ordered after
256
- // any child's own echo/warn output) -- takes already-resolved CallArgs,
257
- // not a raw node+ctx, since Op::PushBuiltinWrap's own runtime handler
258
- // calls this at POP time. See its own doc comment (roof.cpp).
259
- CSGParams computeRoofParams(Evaluator& ev, const CallArgs& args, EvalContext& effCtx);
249
+ // roof() -- roof.cpp. method="voronoi" (the default) is the Voronoi-diagram
250
+ // roof, method="straight" the straight-skeleton one.
251
+ // computeRoofParams: the params half, from already-resolved arguments;
252
+ // it warns ($fs/$fa clamping, unknown method), before the children run.
253
+ CSGParams computeRoofParams(Evaluator& ev, const CallArgs& args, EvalContext& effCtx, const oscad::Position* where);
260
254
  CSGParams resolveRoof(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx);
261
255
  std::vector<ColoredBody> generateRoof(Evaluator& ev, const CSGParams& params,
262
256
  const std::vector<std::unique_ptr<CSGNode>>& children, const oscad::ASTNode& node);
@@ -271,15 +265,28 @@ std::vector<ColoredBody> generateSurface(Evaluator& ev, const CSGParams& params,
271
265
  // operand (and so empties an intersection) -- see resolveCsg.
272
266
  bool emptyStatementIsAnOperand(const oscad::ASTNode& stmt);
273
267
 
274
- // OpenSCAD's sin_degrees/cos_degrees: exact at multiples of 30 and 45 degrees.
268
+ // OpenSCAD's sin_degrees/cos_degrees/tan_degrees/atan2_degrees: exact at
269
+ // multiples of 30 and 45 degrees.
275
270
  double sinDeg(double x);
276
271
  double cosDeg(double x);
272
+ double tanDeg(double x);
273
+ double atan2Deg(double y, double x);
277
274
 
278
- // OpenSCAD's lookup_radius() (primitives_2d.cpp): `d` beats `r`, numbers only.
275
+ // A radius/diameter argument pair: a numeric `d` beats `r`, numbers only.
279
276
  std::optional<double> lookupRadius(Evaluator& ev, const CallArgs& args, std::optional<int> rPos,
280
277
  std::optional<int> dPos, const std::string& rName, const std::string& dName,
281
278
  const oscad::Position* where);
282
279
 
280
+ // "ERROR: <text>" at `where`, for input a primitive repairs and carries on with.
281
+ void emitInputError(Evaluator& ev, const std::string& text, const oscad::Position* where);
282
+
283
+ // Reads polygon() paths or polyhedron() faces (`listName`): each entry a
284
+ // list of point indices. Entries that are not lists and indices that are not
285
+ // numbers are reported as ERRORs and skipped; out-of-range indices are
286
+ // WARNINGs and skipped. Every surviving entry is returned, however short.
287
+ std::vector<std::vector<size_t>> readIndexLists(Evaluator& ev, const ValueList& lists, const std::string& listName,
288
+ size_t pointCount, const oscad::Position* where);
289
+
283
290
  CSGParams resolveText(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx);
284
291
 
285
292
  // The font size text()/textmetrics()/fontmetrics() draw at: `size`
@@ -124,10 +124,8 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
124
124
  // evalFor) -- mirrors _resolve_intersection_for's single
125
125
  // `_check_debug(body_node[0], loop_ctx, expr_level=True)`.
126
126
  if (!bodyNodes.empty()) ev.checkDebug(*bodyNodes.front(), parentCtx, /*forced=*/false, /*exprLevel=*/true);
127
- // One operand per child STATEMENT of every iteration: upstream
128
- // instantiates the children straight into the intersection
129
- // node (control.cc), so they are intersected flat, not
130
- // unioned per iteration first.
127
+ // One operand per child STATEMENT of every iteration: OpenSCAD
128
+ // intersects them flat, not unioned per iteration first.
131
129
  std::vector<const oscad::ASTNode*> assigns, stmts;
132
130
  for (const oscad::ASTNode* stmt : bodyNodes) {
133
131
  if (stmt->kind() == oscad::NodeKind::Assignment) assigns.push_back(stmt);