openscad-cpp-evaluator 1.40.0__tar.gz → 1.41.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 (238) hide show
  1. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/PKG-INFO +1 -1
  2. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/bindings/module.cpp +1 -0
  3. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +3 -0
  4. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/colored_body.hpp +32 -1
  5. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/export.hpp +8 -0
  6. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/segments.hpp +6 -2
  7. openscad_cpp_evaluator-1.41.0/include/openscad_cpp_evaluator/surface_load.hpp +23 -0
  8. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/pyproject.toml +1 -1
  9. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/python/openscad_cpp_evaluator/__init__.py +3 -2
  10. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/booleans.cpp +44 -12
  11. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/builtins.hpp +13 -0
  12. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/control.cpp +30 -42
  13. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/extrude.cpp +93 -55
  14. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/function_builtins.cpp +72 -15
  15. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/import.cpp +33 -2
  16. openscad_cpp_evaluator-1.41.0/src/builtins/primitives_2d.cpp +242 -0
  17. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/primitives_3d.cpp +130 -48
  18. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/segments.cpp +38 -10
  19. openscad_cpp_evaluator-1.41.0/src/builtins/surface.cpp +118 -0
  20. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/topology.cpp +34 -3
  21. openscad_cpp_evaluator-1.41.0/src/builtins/transforms.cpp +443 -0
  22. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/bytecode_compiler.cpp +39 -39
  23. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/bytecode_vm.cpp +5 -2
  24. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/colored_body.cpp +25 -0
  25. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/csg_generate.cpp +44 -17
  26. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/csg_resolve.cpp +2 -1
  27. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/export.cpp +61 -14
  28. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/import/scene_import.cpp +5 -14
  29. openscad_cpp_evaluator-1.41.0/src/import/surface_load.cpp +132 -0
  30. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/CMakeLists.txt +1 -0
  31. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_booleans.cpp +18 -14
  32. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_control_flow.cpp +9 -4
  33. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_import_export.cpp +8 -4
  34. openscad_cpp_evaluator-1.41.0/tests/test_openscad_parity.cpp +370 -0
  35. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_primitives.cpp +29 -5
  36. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_python_bindings.py +9 -6
  37. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_render_expr.cpp +7 -3
  38. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_surface.cpp +49 -18
  39. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_transforms.cpp +12 -5
  40. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/uv.lock +1 -1
  41. openscad_cpp_evaluator-1.40.0/include/openscad_cpp_evaluator/surface_load.hpp +0 -16
  42. openscad_cpp_evaluator-1.40.0/src/builtins/primitives_2d.cpp +0 -152
  43. openscad_cpp_evaluator-1.40.0/src/builtins/surface.cpp +0 -134
  44. openscad_cpp_evaluator-1.40.0/src/builtins/transforms.cpp +0 -417
  45. openscad_cpp_evaluator-1.40.0/src/import/surface_load.cpp +0 -76
  46. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/.github/workflows/ci.yml +0 -0
  47. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/.github/workflows/wheels.yml +0 -0
  48. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/.gitignore +0 -0
  49. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/.gitmodules +0 -0
  50. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/CLAUDE.md +0 -0
  51. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/CMakeLists.txt +0 -0
  52. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/LICENSE +0 -0
  53. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/README.md +0 -0
  54. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/bindings/CMakeLists.txt +0 -0
  55. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/bindings/ast_to_py.cpp +0 -0
  56. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/cmake/embed_font.cmake +0 -0
  57. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/cmake/patch_manifold.cmake +0 -0
  58. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/examples/CMakeLists.txt +0 -0
  59. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/examples/eval_perf_benchmark.cpp +0 -0
  60. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/examples/manifold_cache_reuse.cpp +0 -0
  61. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/examples/minimal_debugger.cpp +0 -0
  62. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  63. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/.gitignore +0 -0
  64. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  65. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  66. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/README.md +0 -0
  67. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  68. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  69. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  70. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  71. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  72. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  73. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  74. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  75. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  76. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  77. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  78. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  79. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  80. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  81. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  82. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  83. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/.DS_Store +0 -0
  84. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  85. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  86. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  87. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  88. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  89. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  90. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  91. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  92. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  93. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  94. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  95. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  96. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  97. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  98. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  99. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  100. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  101. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  102. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  103. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  104. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  105. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  106. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  107. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  108. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  109. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  110. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  111. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  112. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
  113. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  114. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  115. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  116. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  117. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  118. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  119. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  120. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  121. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  122. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  123. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_profile_time.cpp +0 -0
  124. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  125. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  126. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  127. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  128. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  129. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
  130. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  131. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  132. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  133. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  134. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  135. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
  136. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  137. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  138. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
  139. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  140. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  141. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  142. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  143. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  144. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  145. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  146. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  147. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  148. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
  149. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  150. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  151. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  152. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  153. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  154. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  155. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  156. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  157. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  158. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  159. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  160. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  161. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  162. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  163. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
  164. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  165. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/resources/fonts/LICENSE +0 -0
  166. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
  167. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
  168. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
  169. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  170. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/CMakeLists.txt +0 -0
  171. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/call_args.cpp +0 -0
  172. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/color.cpp +0 -0
  173. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/dxf_dim.cpp +0 -0
  174. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/modifiers.cpp +0 -0
  175. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/profile_time.cpp +0 -0
  176. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/registry.cpp +0 -0
  177. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/roof.cpp +0 -0
  178. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/builtins/text.cpp +0 -0
  179. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/coverage.cpp +0 -0
  180. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/css_colors.cpp +0 -0
  181. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/debug/debug_repl.cpp +0 -0
  182. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/debug_profile.cpp +0 -0
  183. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/eval_context.cpp +0 -0
  184. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/eval_error.cpp +0 -0
  185. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/eval_use.cpp +0 -0
  186. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/expr_eval.cpp +0 -0
  187. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/format_closure.cpp +0 -0
  188. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/import/dxf_import.cpp +0 -0
  189. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/import/mesh_import.cpp +0 -0
  190. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/import/svg_import.cpp +0 -0
  191. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/manifold_cache.cpp +0 -0
  192. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/measure_geometry.cpp +0 -0
  193. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/mesh_check.cpp +0 -0
  194. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/stmt_eval.cpp +0 -0
  195. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/text/font_match.cpp +0 -0
  196. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/text/freetype_font_provider.cpp +0 -0
  197. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/text/text_metrics.cpp +0 -0
  198. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/user_calls.cpp +0 -0
  199. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/utf8.cpp +0 -0
  200. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/value.cpp +0 -0
  201. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/xkcd_colors.cpp +0 -0
  202. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/xkcd_colors.hpp +0 -0
  203. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/src/zip_stored.cpp +0 -0
  204. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_bytecode_compiler.cpp +0 -0
  205. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_children_separate.cpp +0 -0
  206. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_cli.cpp +0 -0
  207. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_coverage.cpp +0 -0
  208. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_csg_tree.cpp +0 -0
  209. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_debug_hooks.cpp +0 -0
  210. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_discretizer.cpp +0 -0
  211. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_dxf_svg_import.cpp +0 -0
  212. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_eval_context.cpp +0 -0
  213. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_export.cpp +0 -0
  214. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_expr_eval.cpp +0 -0
  215. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_extrude_roof.cpp +0 -0
  216. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_feature_detection.cpp +0 -0
  217. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_function_builtins.cpp +0 -0
  218. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_helpers.hpp +0 -0
  219. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_include_cache.cpp +0 -0
  220. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_manifold_cache.cpp +0 -0
  221. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_mesh_check.cpp +0 -0
  222. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_multi_color_merge.cpp +0 -0
  223. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_profile_time.cpp +0 -0
  224. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_profiling.cpp +0 -0
  225. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_scope_trail.cpp +0 -0
  226. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_scoping.cpp +0 -0
  227. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_tail_calls.cpp +0 -0
  228. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_text.cpp +0 -0
  229. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_undef_args.cpp +0 -0
  230. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_unexpected_args.cpp +0 -0
  231. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_use.cpp +0 -0
  232. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_value.cpp +0 -0
  233. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_viewport_params.cpp +0 -0
  234. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tests/test_zip_stored.cpp +0 -0
  235. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tools/cli/CMakeLists.txt +0 -0
  236. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tools/cli/cli_lib.cpp +0 -0
  237. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/tools/cli/cli_lib.hpp +0 -0
  238. {openscad_cpp_evaluator-1.40.0 → openscad_cpp_evaluator-1.41.0}/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.40.0
3
+ Version: 1.41.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -134,6 +134,7 @@ const char* roleToString(oscadeval::BodyRole role) {
134
134
  case oscadeval::BodyRole::Highlight: return "highlight";
135
135
  case oscadeval::BodyRole::Background: return "background";
136
136
  case oscadeval::BodyRole::ShowOnly: return "show_only";
137
+ case oscadeval::BodyRole::HighlightGhost: return "highlight_ghost";
137
138
  case oscadeval::BodyRole::Normal:
138
139
  default: return "normal";
139
140
  }
@@ -71,6 +71,9 @@ struct PendingCsgWrap {
71
71
  // Parallel to groupSizes: whether a group that came out EMPTY is still
72
72
  // an operand. See Op::CsgGroupEnd's `a`.
73
73
  std::vector<Value> emptyIsAGroup;
74
+ // Parallel too: whether the statement was a `%` one, which is never an
75
+ // operand. See Op::CsgGroupEnd's `a` (bit 2).
76
+ std::vector<Value> backgroundStmt;
74
77
  size_t groupStartSize = 0;
75
78
  };
76
79
 
@@ -12,7 +12,16 @@
12
12
 
13
13
  namespace oscadeval {
14
14
 
15
- enum class BodyRole { Normal, Highlight, Background, ShowOnly };
15
+ // HighlightGhost is the see-through copy of a `#` operand that an operation
16
+ // (difference, intersection, hull, ...) emits beside its result so the
17
+ // viewport can still show the operand. The operand itself was merged into
18
+ // the result; the ghost is drawing only. It is never an operand again and
19
+ // never exported -- it used to be a plain Highlight body, so an outer
20
+ // boolean used it twice and export wrote it as real geometry:
21
+ // difference(){ cube(2); #translate([1,1,1]) cube(2); } exported volume 15
22
+ // where OpenSCAD writes 7. A `#` with nothing merging it stays Highlight,
23
+ // and exports like any other geometry, as it does upstream.
24
+ enum class BodyRole { Normal, Highlight, Background, ShowOnly, HighlightGhost };
16
25
 
17
26
  // A single piece of evaluated geometry: exactly one of `body` (3D) or
18
27
  // `section` (2D) is set, never both -- mirrors the Python reference's
@@ -178,4 +187,26 @@ inline constexpr double kTopLevel2dHeight = 1.0;
178
187
  std::vector<ColoredBody> toRenderableBodies(const std::vector<ColoredBody>& bodies,
179
188
  double flatHeight = kTopLevel2dHeight);
180
189
 
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
192
+ // geometry (z, and everything out of the plane, simply drops away).
193
+ manifold::mat2x3 projectTo2d(const manifold::mat3x4& m);
194
+
195
+ // Moves a section's carried transform (ColoredBody::sectionXform) into the
196
+ // CrossSection itself, projected onto the plane, and resets it. Every 2D
197
+ // operation does this to its children before it reads them: OpenSCAD's F6
198
+ // has already projected each transform by then, and an operation that
199
+ // ignored the carried one -- union, offset, hull, linear_extrude -- used the
200
+ // shape as if the transform had never happened. False if the projection
201
+ // was singular and the shape was removed (the caller warns).
202
+ bool projectSectionXform(ColoredBody& b);
203
+
204
+ // Applies `m`, projected onto the plane, to a CrossSection. A singular
205
+ // projection -- scale([0,1]), a quarter turn about X -- empties it, as
206
+ // upstream's Polygon2d::transform does, and returns false.
207
+ bool transformSection(manifold::CrossSection& cs, const manifold::mat3x4& m);
208
+
209
+ // Upstream's warning for that case, word for word.
210
+ inline constexpr const char* kZeroScale2dWarning = "Scaling a 2D object with 0 - removing object";
211
+
181
212
  } // namespace oscadeval
@@ -52,6 +52,14 @@ struct ExportObject {
52
52
  // A body Manifold rejected (an open shell is not a solid) can take part in
53
53
  // none of that: it keeps its own triangles and its own object, and its
54
54
  // 1-based index is appended to `openParts` for the caller to warn about.
55
+ // The dimension OpenSCAD's render gives these top-level bodies: that of the
56
+ // first one with geometry (2 or 3), or 0 for none.
57
+ int topLevelDimension(const std::vector<ColoredBody>& bodies);
58
+
59
+ // OpenSCAD's render warnings for a top level that mixes 2D and 3D; export
60
+ // writes only the first object's dimension.
61
+ std::vector<std::string> mixedDimensionWarnings(const std::vector<ColoredBody>& bodies);
62
+
55
63
  std::vector<ExportObject> splitBodiesForExport(const std::vector<ColoredBody>& bodies,
56
64
  std::vector<int>* openParts = nullptr,
57
65
  bool splitComponents = false,
@@ -5,7 +5,9 @@
5
5
 
6
6
  #include <manifold/common.h>
7
7
 
8
+ #include <functional>
8
9
  #include <optional>
10
+ #include <string>
9
11
 
10
12
  namespace oscadeval {
11
13
 
@@ -27,7 +29,8 @@ struct Discretizer {
27
29
  double fa = 12.0;
28
30
  double fs = 2.0;
29
31
 
30
- static Discretizer fromCtx(const EvalContext& ctx);
32
+ // `warn`, when given, receives upstream's clamping warnings.
33
+ static Discretizer fromCtx(const EvalContext& ctx, const std::function<void(const std::string&)>& warn = {});
31
34
  // Stored in, and read back from, a node's params -- they are part of its
32
35
  // cache key, and generate has only the params to go on.
33
36
  static Discretizer fromParams(const CSGParams& params);
@@ -53,6 +56,7 @@ struct Discretizer {
53
56
 
54
57
  // Full-circle segment count from ctx's $fn/$fe/$fa/$fs at radius r;
55
58
  // upstream's primitives fall back to 3.
56
- int fnSegmentsFromCtx(const EvalContext& ctx, double r = 0.0);
59
+ int fnSegmentsFromCtx(const EvalContext& ctx, double r = 0.0,
60
+ const std::function<void(const std::string&)>& warn = {});
57
61
 
58
62
  } // namespace oscadeval
@@ -0,0 +1,23 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+ #include <vector>
5
+
6
+ namespace oscadeval {
7
+
8
+ // Height data for surface(), read as upstream's SurfaceNode reads it: a
9
+ // PNG (by its signature) as 16-bit luminance scaled to 0-100, negated by
10
+ // `invert`, bottom image row at y = 0; anything else as a .dat grid, first
11
+ // line at y = 0, short rows padded with 0. Never throws: a file that cannot
12
+ // be read gives no heights and upstream's warning, and the script carries
13
+ // on. `heights[row * cols + col]`; `minVal` is what the base sits 1 below.
14
+ struct SurfaceData {
15
+ std::vector<double> heights;
16
+ int rows = 0;
17
+ int cols = 0;
18
+ double minVal = 0;
19
+ std::vector<std::string> warnings;
20
+ };
21
+ SurfaceData loadSurface(const std::string& path, bool invert);
22
+
23
+ } // namespace oscadeval
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "1.40.0"
7
+ version = "1.41.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -249,7 +249,8 @@ def _summarize_param(value, max_items: int = 6, max_len: int = 40) -> str:
249
249
  # of kind -- pure internal bookkeeping or already represented structurally
250
250
  # elsewhere in the tree. Mirrors the reference's _DUMP_HIDDEN_PARAM_KEYS.
251
251
  _DUMP_HIDDEN_PARAM_KEYS = frozenset(
252
- {"color", "op", "name", "group_sizes", "empty_is_a_group"})
252
+ {"color", "op", "name", "group_sizes", "empty_is_a_group", "background_stmt",
253
+ "m", "remove"})
253
254
 
254
255
  # Auto-generated tessellation data (not user-authored) for every kind except
255
256
  # polyhedron, where the equivalent data *is* the user's own points/faces.
@@ -520,7 +521,7 @@ class ColoredBody:
520
521
  section: object = None # kept for API parity (always None here)
521
522
  flat_preview: bool = False
522
523
  tri_colors: Optional[object] = None # (numTri, 4) float32 ndarray, real multi-color CSG merges only
523
- role: str = "normal" # "normal" | "highlight" | "background" | "show_only"
524
+ role: str = "normal" # "normal" | "highlight" | "highlight_ghost" | "background" | "show_only"
524
525
 
525
526
 
526
527
  def bodies_from_dicts(body_dicts) -> list:
@@ -33,17 +33,28 @@ RoleSplit splitByRole(const std::vector<ColoredBody>& bodies) {
33
33
  // boolean would silently zero the whole operation (the same failure
34
34
  // mode invalid operands caused before they were filtered out).
35
35
  for (const ColoredBody& c : bodies) {
36
- if (c.isDisplayOnly() && c.role != BodyRole::Background && c.role != BodyRole::ShowOnly) {
36
+ if (c.isDisplayOnly() && c.role != BodyRole::Background && c.role != BodyRole::ShowOnly &&
37
+ c.role != BodyRole::HighlightGhost) {
37
38
  r.displayOnly.push_back(c);
38
39
  }
39
40
  }
40
41
  for (const ColoredBody& c : bodies) {
41
- if (c.role != BodyRole::Background && c.role != BodyRole::ShowOnly && !c.isDisplayOnly()) {
42
+ if (c.role != BodyRole::Background && c.role != BodyRole::ShowOnly && c.role != BodyRole::HighlightGhost &&
43
+ !c.isDisplayOnly()) {
42
44
  r.foreground.push_back(c);
43
45
  }
44
46
  }
47
+ // A `#` operand is merged like any other (it is in `foreground` above)
48
+ // AND drawn again as a ghost; a ghost from deeper down just rides along.
45
49
  for (const ColoredBody& c : r.foreground) {
46
- if (c.role == BodyRole::Highlight) r.highlight.push_back(c);
50
+ if (c.role == BodyRole::Highlight) {
51
+ ColoredBody ghost = c;
52
+ ghost.role = BodyRole::HighlightGhost;
53
+ r.highlight.push_back(std::move(ghost));
54
+ }
55
+ }
56
+ for (const ColoredBody& c : bodies) {
57
+ if (c.role == BodyRole::HighlightGhost) r.highlight.push_back(c);
47
58
  }
48
59
  for (const ColoredBody& c : bodies) {
49
60
  if (c.role == BodyRole::ShowOnly) r.showOnly.push_back(c);
@@ -82,6 +93,13 @@ std::optional<manifold::CrossSection> toCrossSection(const std::vector<ColoredBo
82
93
  // alongside real ManifoldCache/provenance work if per-triangle color
83
94
  // through a merge is needed).
84
95
 
96
+ bool emptyStatementIsAnOperand(const oscad::ASTNode& stmt) {
97
+ const oscad::NodeKind k = stmt.kind();
98
+ return k == oscad::NodeKind::ModularCall || k == oscad::NodeKind::ModularFor ||
99
+ k == oscad::NodeKind::ModularIntersectionFor || k == oscad::NodeKind::ModularLet ||
100
+ k == oscad::NodeKind::ModularModifierShowOnly || k == oscad::NodeKind::ModularModifierHighlight;
101
+ }
102
+
85
103
  CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
86
104
  const std::string& op = node.name->name;
87
105
  // union/difference/intersection take no positional arguments in real
@@ -110,6 +128,7 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
110
128
 
111
129
  std::vector<Value> groupSizes;
112
130
  std::vector<Value> emptyIsAGroup;
131
+ std::vector<Value> backgroundStmt;
113
132
  groupSizes.reserve(geoNodes.size());
114
133
  emptyIsAGroup.reserve(geoNodes.size());
115
134
  for (const oscad::ASTNode* geoNode : geoNodes) {
@@ -130,15 +149,8 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
130
149
  // for `if(false) sphere(6)`, `{ }` and `*cube(1)`, and comes out
131
150
  // empty for `for(i=[1:0]) sphere(6)`, `union(){}`, `group(){}` and
132
151
  // a call to an empty user module.
133
- const oscad::NodeKind k = geoNode->kind();
134
- emptyIsAGroup.push_back(Value{
135
- k == oscad::NodeKind::ModularCall ||
136
- k == oscad::NodeKind::ModularFor ||
137
- k == oscad::NodeKind::ModularIntersectionFor ||
138
- k == oscad::NodeKind::ModularLet ||
139
- k == oscad::NodeKind::ModularModifierShowOnly ||
140
- k == oscad::NodeKind::ModularModifierHighlight ||
141
- k == oscad::NodeKind::ModularModifierBackground});
152
+ emptyIsAGroup.push_back(Value{emptyStatementIsAnOperand(*geoNode)});
153
+ backgroundStmt.push_back(Value{geoNode->kind() == oscad::NodeKind::ModularModifierBackground});
142
154
  }
143
155
 
144
156
  CSGParams params;
@@ -146,6 +158,7 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
146
158
  params["group_sizes"] = Value{makeList(std::move(groupSizes))};
147
159
  params["empty_is_a_group"] =
148
160
  Value{makeList(std::move(emptyIsAGroup))};
161
+ params["background_stmt"] = Value{makeList(std::move(backgroundStmt))};
149
162
  return params;
150
163
  }
151
164
 
@@ -314,6 +327,11 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
314
327
  const std::string& op = std::get<std::string>(params.at("op"));
315
328
  const auto& groupSizes = std::get<ListPtr>(params.at("group_sizes"))->items;
316
329
  const auto emptyIsAGroupIt = params.find("empty_is_a_group");
330
+ const auto backgroundStmtIt = params.find("background_stmt");
331
+ const auto* backgroundStmt =
332
+ backgroundStmtIt != params.end() && std::holds_alternative<ListPtr>(backgroundStmtIt->second)
333
+ ? &std::get<ListPtr>(backgroundStmtIt->second)->items
334
+ : nullptr;
317
335
  const ListItems* emptyIsAGroup =
318
336
  emptyIsAGroupIt == params.end()
319
337
  ? nullptr
@@ -374,6 +392,20 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
374
392
  }
375
393
 
376
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
397
+ // NEXT statement is the minuend of a difference(), and an
398
+ // intersection() is not cancelled by it. It was taken as an empty
399
+ // operand, which emptied both. Only the `%` statement itself: a
400
+ // module or union() holding nothing but `%` is still an (empty)
401
+ // operand there.
402
+ const bool isBackgroundStmt = backgroundStmt && thisStmt < backgroundStmt->size() &&
403
+ std::holds_alternative<bool>((*backgroundStmt)[thisStmt]) &&
404
+ std::get<bool>((*backgroundStmt)[thisStmt]);
405
+ if (isBackgroundStmt) {
406
+ allBg.insert(allBg.end(), split.background.begin(), split.background.end());
407
+ continue;
408
+ }
377
409
  allBg.insert(allBg.end(), split.background.begin(), split.background.end());
378
410
  allHi.insert(allHi.end(), split.highlight.begin(), split.highlight.end());
379
411
  allSo.insert(allSo.end(), split.showOnly.begin(), split.showOnly.end());
@@ -267,6 +267,19 @@ std::vector<ColoredBody> generateSurface(Evaluator& ev, const CSGParams& params,
267
267
  const std::vector<std::unique_ptr<CSGNode>>& children, const oscad::ASTNode& node);
268
268
 
269
269
  // text() -- text.cpp.
270
+ // Whether a statement that produced no geometry still counts as a boolean
271
+ // operand (and so empties an intersection) -- see resolveCsg.
272
+ bool emptyStatementIsAnOperand(const oscad::ASTNode& stmt);
273
+
274
+ // OpenSCAD's sin_degrees/cos_degrees: exact at multiples of 30 and 45 degrees.
275
+ double sinDeg(double x);
276
+ double cosDeg(double x);
277
+
278
+ // OpenSCAD's lookup_radius() (primitives_2d.cpp): `d` beats `r`, numbers only.
279
+ std::optional<double> lookupRadius(Evaluator& ev, const CallArgs& args, std::optional<int> rPos,
280
+ std::optional<int> dPos, const std::string& rName, const std::string& dName,
281
+ const oscad::Position* where);
282
+
270
283
  CSGParams resolveText(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx);
271
284
 
272
285
  // The font size text()/textmetrics()/fontmetrics() draw at: `size`
@@ -106,6 +106,8 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
106
106
  const std::vector<const oscad::ASTNode*> bodyNodes = ev.expandChildStatements(node.body, ctx);
107
107
 
108
108
  std::vector<Value> groupSizes;
109
+ std::vector<Value> emptyIsAGroup;
110
+ std::vector<Value> backgroundStmt;
109
111
 
110
112
  // Each dimension's own RHS is evaluated against `parentCtx` (not
111
113
  // upfront against the original `ctx`), re-evaluated on every entry
@@ -121,9 +123,25 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
121
123
  // evalFor) -- mirrors _resolve_intersection_for's single
122
124
  // `_check_debug(body_node[0], loop_ctx, expr_level=True)`.
123
125
  if (!bodyNodes.empty()) ev.checkDebug(*bodyNodes.front(), parentCtx, /*forced=*/false, /*exprLevel=*/true);
124
- const size_t before = ev.currentTreeFrameSize();
125
- ev.evalChildren(bodyNodes, parentCtx);
126
- groupSizes.push_back(Value{static_cast<double>(ev.currentTreeFrameSize() - before)});
126
+ // One operand per child STATEMENT of every iteration: upstream
127
+ // instantiates the children straight into the intersection
128
+ // node (control.cc), so they are intersected flat, not
129
+ // unioned per iteration first.
130
+ std::vector<const oscad::ASTNode*> assigns, stmts;
131
+ for (const oscad::ASTNode* stmt : bodyNodes) {
132
+ if (stmt->kind() == oscad::NodeKind::Assignment) assigns.push_back(stmt);
133
+ else if (stmt->kind() != oscad::NodeKind::ModuleDeclaration &&
134
+ stmt->kind() != oscad::NodeKind::FunctionDeclaration)
135
+ stmts.push_back(stmt);
136
+ }
137
+ if (!assigns.empty()) ev.evalChildren(assigns, parentCtx);
138
+ for (const oscad::ASTNode* stmt : stmts) {
139
+ const size_t before = ev.currentTreeFrameSize();
140
+ ev.evalChildren(std::vector<const oscad::ASTNode*>{stmt}, parentCtx);
141
+ groupSizes.push_back(Value{static_cast<double>(ev.currentTreeFrameSize() - before)});
142
+ emptyIsAGroup.push_back(Value{emptyStatementIsAnOperand(*stmt)});
143
+ backgroundStmt.push_back(Value{stmt->kind() == oscad::NodeKind::ModularModifierBackground});
144
+ }
127
145
  return;
128
146
  }
129
147
  const auto& assign = node.assignments[depth];
@@ -142,49 +160,19 @@ CSGParams resolveIntersectionFor(Evaluator& ev, const oscad::ModularIntersection
142
160
 
143
161
  CSGParams params;
144
162
  params["group_sizes"] = Value{makeList(std::move(groupSizes))};
163
+ params["empty_is_a_group"] = Value{makeList(std::move(emptyIsAGroup))};
164
+ params["background_stmt"] = Value{makeList(std::move(backgroundStmt))};
145
165
  return params;
146
166
  }
147
167
 
148
- std::vector<ColoredBody> generateIntersectionFor(Evaluator&, const CSGParams& params,
168
+ std::vector<ColoredBody> generateIntersectionFor(Evaluator& ev, const CSGParams& params,
149
169
  const std::vector<std::unique_ptr<CSGNode>>& children,
150
- const oscad::ASTNode&) {
151
- const auto& groupSizes = std::get<ListPtr>(params.at("group_sizes"))->items;
152
- std::vector<ColoredBody> iterations;
153
- size_t idx = 0;
154
- for (const Value& sv : groupSizes) {
155
- const size_t size = static_cast<size_t>(std::get<double>(sv));
156
- std::vector<ColoredBody> stmtBodies = flattenCsgTree(children, idx, size);
157
- idx += size;
158
- if (!stmtBodies.empty()) iterations.push_back(combineBodies(stmtBodies));
159
- }
160
- if (iterations.empty()) return {};
161
-
162
- std::vector<ColoredBody> bodies3d;
163
- for (const ColoredBody& c : iterations) {
164
- if (c.body) bodies3d.push_back(c);
165
- }
166
- if (!bodies3d.empty()) {
167
- manifold::Manifold result = *bodies3d.front().body;
168
- for (size_t i = 1; i < bodies3d.size(); ++i) result = result ^ *bodies3d[i].body;
169
- ColoredBody cb;
170
- cb.body = std::move(result);
171
- cb.color = bodies3d.front().color;
172
- return {cb};
173
- }
174
-
175
- std::vector<ColoredBody> sections;
176
- for (const ColoredBody& c : iterations) {
177
- if (c.section) sections.push_back(c);
178
- }
179
- if (!sections.empty()) {
180
- manifold::CrossSection result = *sections.front().section;
181
- for (size_t i = 1; i < sections.size(); ++i) result = result ^ *sections[i].section;
182
- ColoredBody cb;
183
- cb.section = std::move(result);
184
- cb.color = iterations.front().color;
185
- return {cb};
186
- }
187
- return {};
170
+ const oscad::ASTNode& node) {
171
+ // The same operand rules as intersection() itself -- empty statements,
172
+ // `%` scenery, `#` ghosts, 2D vs 3D -- over the flat statement list.
173
+ CSGParams p = params;
174
+ p["op"] = Value{std::string("intersection")};
175
+ return generateCsg(ev, p, children, node);
188
176
  }
189
177
 
190
178
  } // namespace oscadeval