openscad-cpp-evaluator 1.11.0__tar.gz → 1.12.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 (215) hide show
  1. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/CLAUDE.md +12 -0
  2. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/PKG-INFO +1 -1
  3. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/pyproject.toml +1 -1
  4. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/booleans.cpp +81 -14
  5. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_booleans.cpp +115 -0
  6. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/.github/workflows/ci.yml +0 -0
  7. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/.github/workflows/wheels.yml +0 -0
  8. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/.gitignore +0 -0
  9. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/.gitmodules +0 -0
  10. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/CMakeLists.txt +0 -0
  11. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/LICENSE +0 -0
  12. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/README.md +0 -0
  13. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/bindings/CMakeLists.txt +0 -0
  14. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/bindings/ast_to_py.cpp +0 -0
  15. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/bindings/module.cpp +0 -0
  16. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/cmake/embed_font.cmake +0 -0
  17. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/examples/CMakeLists.txt +0 -0
  18. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/examples/eval_perf_benchmark.cpp +0 -0
  19. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/examples/manifold_cache_reuse.cpp +0 -0
  20. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/examples/minimal_debugger.cpp +0 -0
  21. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  22. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/.gitignore +0 -0
  23. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  24. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  25. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/README.md +0 -0
  26. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  27. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  28. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  29. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  30. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  31. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  32. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  33. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  34. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  35. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  36. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  37. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  38. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  39. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  40. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  41. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  42. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  43. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  44. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  45. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  46. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  47. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  48. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  49. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  50. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  51. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  52. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  53. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  54. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  55. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  56. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  57. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  58. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  59. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  60. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  61. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  62. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  63. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  64. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  65. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  66. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  67. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  68. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  69. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  70. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  71. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  72. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  73. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  74. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  75. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  76. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  77. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  78. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  79. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  80. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  81. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  82. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  83. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  84. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  85. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
  86. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  87. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  88. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  89. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  90. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  91. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
  92. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  93. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  94. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  95. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  96. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  97. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  98. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  99. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  100. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  101. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  102. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  103. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  104. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  105. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
  106. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
  107. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  108. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  109. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  110. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  111. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  112. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  113. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  114. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  115. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  116. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  117. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  118. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  119. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  120. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  121. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  122. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  123. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
  124. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  125. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
  126. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/resources/fonts/LICENSE +0 -0
  127. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  128. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/CMakeLists.txt +0 -0
  129. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/builtins.hpp +0 -0
  130. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/call_args.cpp +0 -0
  131. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/color.cpp +0 -0
  132. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/control.cpp +0 -0
  133. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/dxf_dim.cpp +0 -0
  134. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/extrude.cpp +0 -0
  135. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/function_builtins.cpp +0 -0
  136. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/import.cpp +0 -0
  137. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/modifiers.cpp +0 -0
  138. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/primitives_2d.cpp +0 -0
  139. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/primitives_3d.cpp +0 -0
  140. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/registry.cpp +0 -0
  141. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/roof.cpp +0 -0
  142. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/segments.cpp +0 -0
  143. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/surface.cpp +0 -0
  144. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/text.cpp +0 -0
  145. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/topology.cpp +0 -0
  146. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/transforms.cpp +0 -0
  147. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/bytecode_compiler.cpp +0 -0
  148. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/bytecode_vm.cpp +0 -0
  149. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/colored_body.cpp +0 -0
  150. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/csg_generate.cpp +0 -0
  151. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/csg_resolve.cpp +0 -0
  152. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/css_colors.cpp +0 -0
  153. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/debug/debug_repl.cpp +0 -0
  154. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/debug_profile.cpp +0 -0
  155. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/eval_context.cpp +0 -0
  156. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/eval_error.cpp +0 -0
  157. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/eval_use.cpp +0 -0
  158. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/export.cpp +0 -0
  159. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/expr_eval.cpp +0 -0
  160. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/format_closure.cpp +0 -0
  161. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/import/dxf_import.cpp +0 -0
  162. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/import/mesh_import.cpp +0 -0
  163. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/import/surface_load.cpp +0 -0
  164. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/import/svg_import.cpp +0 -0
  165. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/manifold_cache.cpp +0 -0
  166. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/measure_geometry.cpp +0 -0
  167. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/mesh_check.cpp +0 -0
  168. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/stmt_eval.cpp +0 -0
  169. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/text/font_match.cpp +0 -0
  170. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/text/freetype_font_provider.cpp +0 -0
  171. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/text/text_metrics.cpp +0 -0
  172. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/user_calls.cpp +0 -0
  173. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/utf8.cpp +0 -0
  174. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/value.cpp +0 -0
  175. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/src/zip_stored.cpp +0 -0
  176. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/CMakeLists.txt +0 -0
  177. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_bytecode_compiler.cpp +0 -0
  178. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_children_separate.cpp +0 -0
  179. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_cli.cpp +0 -0
  180. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_control_flow.cpp +0 -0
  181. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_csg_tree.cpp +0 -0
  182. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_debug_hooks.cpp +0 -0
  183. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_dxf_svg_import.cpp +0 -0
  184. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_eval_context.cpp +0 -0
  185. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_export.cpp +0 -0
  186. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_expr_eval.cpp +0 -0
  187. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_extrude_roof.cpp +0 -0
  188. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_feature_detection.cpp +0 -0
  189. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_function_builtins.cpp +0 -0
  190. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_helpers.hpp +0 -0
  191. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_import_export.cpp +0 -0
  192. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_include_cache.cpp +0 -0
  193. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_manifold_cache.cpp +0 -0
  194. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_mesh_check.cpp +0 -0
  195. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_multi_color_merge.cpp +0 -0
  196. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_primitives.cpp +0 -0
  197. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_profiling.cpp +0 -0
  198. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_python_bindings.py +0 -0
  199. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_render_expr.cpp +0 -0
  200. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_scope_trail.cpp +0 -0
  201. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_scoping.cpp +0 -0
  202. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_surface.cpp +0 -0
  203. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_tail_calls.cpp +0 -0
  204. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_text.cpp +0 -0
  205. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_transforms.cpp +0 -0
  206. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_unexpected_args.cpp +0 -0
  207. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_use.cpp +0 -0
  208. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_value.cpp +0 -0
  209. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_viewport_params.cpp +0 -0
  210. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tests/test_zip_stored.cpp +0 -0
  211. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tools/cli/CMakeLists.txt +0 -0
  212. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tools/cli/cli_lib.cpp +0 -0
  213. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tools/cli/cli_lib.hpp +0 -0
  214. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/tools/cli/main.cpp +0 -0
  215. {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.12.0}/uv.lock +0 -0
@@ -793,6 +793,18 @@ grep for `ponytail:`.
793
793
  color instead of preserving each part's own, matching real OpenSCAD's actual behavior once fixed
794
794
  (cross-checked triangle-color-count-and-values against the Python reference directly, not just
795
795
  “does it run”).
796
+ **2D cannot use any of that, and keeps colour geometrically instead** (`Part2d`, same file): a
797
+ `CrossSection` is contours, not a mesh, so nothing in it remembers which child an edge came from
798
+ and there is no provenance for `attachTriColors` to read back. So the 2D accumulator holds **one
799
+ part per colour** rather than one merged section — same-coloured children still merge into one
800
+ part, a later statement notches what it covers out of the earlier parts (painter's order, the
801
+ rule `splitBodiesForExport` applies to overlapping 3D solids), `difference`/`intersection` apply
802
+ to every part, and a part cut away entirely is dropped. `generateCsg` then returns one
803
+ `ColoredBody` per surviving part, so **a 2D `union()` of differently-coloured children returns
804
+ several bodies where it used to return one**. Reported as a user bug: `union() { color("red")
805
+ square(10); color("blue") translate([12,0]) square(10); }` drew both squares red, where OpenSCAD
806
+ draws red and blue (verified by pixel-sampling both binaries' PNG output). `linear_extrude` of
807
+ such a union still drops colour entirely — checked against the real binary, which does the same.
796
808
  - `src/builtins/primitives_3d.cpp` — `sphere(style=)` is a BelfrySCAD extension naming the
797
809
  tessellation, using BOSL2's five `spheroid()` style names and constructions: `"orig"` (the default,
798
810
  and what OpenSCAD's own sphere() builds — rings offset half a step from the poles, no pole vertex),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 1.11.0
3
+ Version: 1.12.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "1.11.0"
7
+ version = "1.12.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -201,6 +201,57 @@ void attachTriColors(Evaluator& ev, ColoredBody& cb) {
201
201
  cb.triColors = std::move(triColors);
202
202
  }
203
203
 
204
+ // One colour's worth of 2D result.
205
+ //
206
+ // 3D recovers per-child colour AFTER the merge, from Manifold's own
207
+ // per-triangle provenance (attachTriColors above). A CrossSection has no
208
+ // such thing -- it is contours, not a mesh, and nothing in it remembers
209
+ // which child a given edge came from. So 2D has to keep colour
210
+ // GEOMETRICALLY instead: one part per colour, each notched by whatever is
211
+ // drawn over it later. That is the same painter's-order rule
212
+ // splitBodiesForExport applies to overlapping 3D solids, and it is what
213
+ // `union() { color("red") square(10); color("blue") ... }` needs to come
214
+ // out as two coloured shapes instead of one shape wearing the first
215
+ // child's colour.
216
+ struct Part2d {
217
+ std::optional<std::array<float, 4>> color;
218
+ manifold::CrossSection section;
219
+ };
220
+
221
+ // Appends `add` to `parts`, merging into an existing part of the same
222
+ // colour so `union() { color("red") a; color("red") b; }` stays one body.
223
+ void addPart(std::vector<Part2d>& parts, const std::optional<std::array<float, 4>>& color,
224
+ const manifold::CrossSection& section) {
225
+ for (Part2d& p : parts) {
226
+ if (p.color == color) {
227
+ p.section = p.section + section;
228
+ return;
229
+ }
230
+ }
231
+ parts.push_back({color, section});
232
+ }
233
+
234
+ // The 2D operands of one statement, grouped by colour.
235
+ std::vector<Part2d> partsOf(const std::vector<ColoredBody>& sections2d) {
236
+ std::vector<Part2d> parts;
237
+ for (const ColoredBody& c : sections2d) addPart(parts, c.color, *c.section);
238
+ return parts;
239
+ }
240
+
241
+ // Every part's section unioned -- the shape the statement covers,
242
+ // whatever colours it is in.
243
+ manifold::CrossSection coveredBy(const std::vector<Part2d>& parts) {
244
+ manifold::CrossSection all;
245
+ for (const Part2d& p : parts) all = all + p.section;
246
+ return all;
247
+ }
248
+
249
+ void dropEmptyParts(std::vector<Part2d>& parts) {
250
+ parts.erase(std::remove_if(parts.begin(), parts.end(),
251
+ [](const Part2d& p) { return p.section.IsEmpty(); }),
252
+ parts.end());
253
+ }
254
+
204
255
  } // namespace
205
256
 
206
257
  std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, const std::vector<std::unique_ptr<CSGNode>>& children,
@@ -222,7 +273,12 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
222
273
  // part-way. difference and intersection still see one dimension only:
223
274
  // applyDimensionRules drops the mismatch before it gets here, so for
224
275
  // them just one of these is ever populated.
225
- std::optional<ColoredBody> res3d, res2d;
276
+ std::optional<ColoredBody> res3d;
277
+ // 2D keeps one entry per colour rather than one merged section; see
278
+ // Part2d. `have2d` distinguishes "no 2D operand yet" from "every 2D
279
+ // part has been cut away", which matters to difference().
280
+ std::vector<Part2d> res2d;
281
+ bool have2d = false;
226
282
  size_t idx = 0;
227
283
 
228
284
  size_t stmtIndex = 0;
@@ -282,10 +338,11 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
282
338
  // union just skips the empty contributor and keeps going.
283
339
  if (op == "intersection") {
284
340
  res3d.reset();
285
- res2d.reset();
341
+ res2d.clear();
342
+ have2d = false;
286
343
  break;
287
344
  }
288
- if (op == "difference" && !res3d && !res2d) break;
345
+ if (op == "difference" && !res3d && !have2d) break;
289
346
  continue;
290
347
  }
291
348
 
@@ -309,20 +366,25 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
309
366
  }
310
367
  }
311
368
  if (!sections2d.empty()) {
312
- manifold::CrossSection grp = *sections2d.front().section;
313
- for (size_t i = 1; i < sections2d.size(); ++i) grp = grp + *sections2d[i].section;
314
- if (!res2d) {
315
- ColoredBody cb;
316
- cb.section = std::move(grp);
317
- cb.color = sections2d.front().color;
318
- res2d = std::move(cb);
369
+ std::vector<Part2d> stmtParts = partsOf(sections2d);
370
+ const manifold::CrossSection grp = coveredBy(stmtParts);
371
+ if (!have2d) {
372
+ res2d = std::move(stmtParts);
373
+ have2d = true;
319
374
  } else if (op == "union") {
320
- res2d->section = *res2d->section + grp;
375
+ // Later wins the overlap: notch what is already there by
376
+ // everything this statement covers, then add this
377
+ // statement's parts. Same rule as two overlapping 3D
378
+ // solids of different colours, and the same thing a
379
+ // painter does.
380
+ for (Part2d& p : res2d) p.section = p.section - grp;
381
+ for (Part2d& np : stmtParts) addPart(res2d, np.color, np.section);
321
382
  } else if (op == "difference") {
322
- res2d->section = *res2d->section - grp;
383
+ for (Part2d& p : res2d) p.section = p.section - grp;
323
384
  } else if (op == "intersection") {
324
- res2d->section = *res2d->section ^ grp;
385
+ for (Part2d& p : res2d) p.section = p.section ^ grp;
325
386
  }
387
+ dropEmptyParts(res2d);
326
388
  }
327
389
  }
328
390
 
@@ -330,7 +392,12 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
330
392
 
331
393
  std::vector<ColoredBody> result;
332
394
  if (res3d) result.push_back(std::move(*res3d));
333
- if (res2d) result.push_back(std::move(*res2d));
395
+ for (Part2d& p : res2d) {
396
+ ColoredBody cb;
397
+ cb.color = p.color;
398
+ cb.section = std::move(p.section);
399
+ result.push_back(std::move(cb));
400
+ }
334
401
  result.insert(result.end(), allBg.begin(), allBg.end());
335
402
  result.insert(result.end(), allHi.begin(), allHi.end());
336
403
  result.insert(result.end(), allSo.begin(), allSo.end());
@@ -1439,3 +1439,118 @@ TEST(LevelSet, AGridFieldIsAlsoCutCleanlyAtTheBox) {
1439
1439
  ASSERT_EQ(e.bodies.size(), 1u);
1440
1440
  EXPECT_NEAR(soleBody(e).Volume(), 32000.0, 40.0); // one sample layer of slack
1441
1441
  }
1442
+
1443
+ // -- 2D union keeps every colour (bug report: "multiple colors inside a
1444
+ // union(), only one color is used") -----------------------------------
1445
+
1446
+ namespace {
1447
+
1448
+ // (colour, area) per 2D body, in result order.
1449
+ std::vector<std::pair<std::array<float, 4>, double>> colouredAreas(const std::vector<ColoredBody>& bodies) {
1450
+ std::vector<std::pair<std::array<float, 4>, double>> out;
1451
+ for (const ColoredBody& b : bodies) {
1452
+ if (!b.section) continue;
1453
+ out.emplace_back(b.color.value_or(std::array<float, 4>{0, 0, 0, 0}), b.section->Area());
1454
+ }
1455
+ return out;
1456
+ }
1457
+
1458
+ constexpr std::array<float, 4> kRed{1, 0, 0, 1};
1459
+ constexpr std::array<float, 4> kBlue{0, 0, 1, 1};
1460
+
1461
+ } // namespace
1462
+
1463
+ TEST(Union2dColor, KeepsOneBodyPerColour) {
1464
+ // A CrossSection has no per-edge provenance for attachTriColors to read
1465
+ // back afterwards, so 2D keeps colour by staying in separate parts.
1466
+ // Before this, both squares came out red -- the first child's colour
1467
+ // for the whole merged section, where OpenSCAD draws red AND blue.
1468
+ Evaluated e = evalSrc("union() { color(\"red\") square(10); color(\"blue\") translate([12,0]) square(10); }");
1469
+ const auto parts = colouredAreas(e.bodies);
1470
+ ASSERT_EQ(parts.size(), 2u);
1471
+ EXPECT_EQ(parts[0].first, kRed);
1472
+ EXPECT_EQ(parts[1].first, kBlue);
1473
+ EXPECT_NEAR(parts[0].second, 100.0, 1e-6);
1474
+ EXPECT_NEAR(parts[1].second, 100.0, 1e-6);
1475
+ }
1476
+
1477
+ TEST(Union2dColor, OneColourStaysOneBody) {
1478
+ // Splitting per colour must not split per child: two red squares are
1479
+ // one red shape, as they always were.
1480
+ Evaluated e = evalSrc("union() { color(\"red\") square(10); color(\"red\") translate([12,0]) square(10); }");
1481
+ const auto parts = colouredAreas(e.bodies);
1482
+ ASSERT_EQ(parts.size(), 1u);
1483
+ EXPECT_EQ(parts[0].first, kRed);
1484
+ EXPECT_NEAR(parts[0].second, 200.0, 1e-6);
1485
+ }
1486
+
1487
+ TEST(Union2dColor, AnUncolouredUnionIsStillASingleBody) {
1488
+ Evaluated e = evalSrc("union() { square(10); translate([12,0]) square(10); }");
1489
+ ASSERT_EQ(e.bodies.size(), 1u);
1490
+ ASSERT_TRUE(e.bodies[0].section.has_value());
1491
+ EXPECT_FALSE(e.bodies[0].color.has_value());
1492
+ }
1493
+
1494
+ TEST(Union2dColor, TheLaterColourWinsAnOverlap) {
1495
+ // Painter's order, the same rule splitBodiesForExport applies to
1496
+ // overlapping 3D solids -- and what OpenSCAD's own preview shows.
1497
+ Evaluated e = evalSrc(
1498
+ "union() { color(\"red\") square(10); color(\"blue\") translate([5,5]) square(10); }");
1499
+ const auto parts = colouredAreas(e.bodies);
1500
+ ASSERT_EQ(parts.size(), 2u);
1501
+ EXPECT_EQ(parts[0].first, kRed);
1502
+ EXPECT_EQ(parts[1].first, kBlue);
1503
+ // Blue keeps its whole square; red is notched by the 5x5 overlap.
1504
+ EXPECT_NEAR(parts[1].second, 100.0, 1e-6);
1505
+ EXPECT_NEAR(parts[0].second, 75.0, 1e-6);
1506
+ }
1507
+
1508
+ TEST(Union2dColor, DifferenceCutsEveryColouredPart) {
1509
+ Evaluated e = evalSrc(
1510
+ "difference() {"
1511
+ " union() { color(\"red\") square(10); color(\"blue\") translate([10,0]) square(10); }"
1512
+ " translate([5,0]) square(10);"
1513
+ "}");
1514
+ const auto parts = colouredAreas(e.bodies);
1515
+ ASSERT_EQ(parts.size(), 2u);
1516
+ // The cut spans both: 5 wide off red's right, 5 off blue's left.
1517
+ EXPECT_NEAR(parts[0].second, 50.0, 1e-6);
1518
+ EXPECT_NEAR(parts[1].second, 50.0, 1e-6);
1519
+ }
1520
+
1521
+ TEST(Union2dColor, IntersectionKeepsColoursToo) {
1522
+ Evaluated e = evalSrc(
1523
+ "intersection() {"
1524
+ " union() { color(\"red\") square(10); color(\"blue\") translate([10,0]) square(10); }"
1525
+ " translate([5,0]) square(10);"
1526
+ "}");
1527
+ const auto parts = colouredAreas(e.bodies);
1528
+ ASSERT_EQ(parts.size(), 2u);
1529
+ EXPECT_EQ(parts[0].first, kRed);
1530
+ EXPECT_EQ(parts[1].first, kBlue);
1531
+ EXPECT_NEAR(parts[0].second, 50.0, 1e-6);
1532
+ EXPECT_NEAR(parts[1].second, 50.0, 1e-6);
1533
+ }
1534
+
1535
+ TEST(Union2dColor, APartCutAwayEntirelyIsDropped) {
1536
+ Evaluated e = evalSrc(
1537
+ "difference() {"
1538
+ " union() { color(\"red\") square(10); color(\"blue\") translate([20,0]) square(10); }"
1539
+ " square(10);"
1540
+ "}");
1541
+ const auto parts = colouredAreas(e.bodies);
1542
+ ASSERT_EQ(parts.size(), 1u);
1543
+ EXPECT_EQ(parts[0].first, kBlue);
1544
+ }
1545
+
1546
+ TEST(Union2dColor, ExtrudingAColouredUnionStillDropsColour) {
1547
+ // Not a bug, and checked against the real binary: OpenSCAD's own
1548
+ // linear_extrude of coloured 2D children draws the default colour too.
1549
+ // Splitting 2D by colour must not accidentally start colouring these.
1550
+ Evaluated e = evalSrc(
1551
+ "linear_extrude(5) union() { color(\"red\") square(10); color(\"blue\") translate([12,0]) square(10); }");
1552
+ ASSERT_EQ(e.bodies.size(), 1u);
1553
+ ASSERT_TRUE(e.bodies[0].body.has_value());
1554
+ EXPECT_FALSE(e.bodies[0].color.has_value());
1555
+ EXPECT_NEAR(e.bodies[0].body->Volume(), 1000.0, 1e-6);
1556
+ }