openscad-cpp-evaluator 1.11.0__tar.gz → 1.13.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.
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/CLAUDE.md +30 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/bindings/module.cpp +7 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/evaluator.hpp +7 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/booleans.cpp +88 -15
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/color.cpp +31 -1
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/topology.cpp +8 -1
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/csg_generate.cpp +9 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_booleans.cpp +194 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/README.md +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/uv.lock +0 -0
|
@@ -793,6 +793,36 @@ 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
|
+
Two things that pipeline depends on, both learned from BelfrySCAD #372 (`union() { color("red")
|
|
797
|
+
stroke(...); text(); }` came out entirely red):
|
|
798
|
+
**`color()` records its colour against the body's RUN IDS**, not only in `cb.color`
|
|
799
|
+
(`recordRunColors`, `color.cpp`). `tagGenerated()` covers a body coloured at birth — the colour
|
|
800
|
+
reaches a primitive through the context — but not one that already existed when colour was applied
|
|
801
|
+
to it, which is every module that wraps FORWARDED children: `module setcolor(clr) { color(clr)
|
|
802
|
+
children(); }` (BOSL2's `stroke()` has exactly that) generates the children in the caller's
|
|
803
|
+
colourless context, so nothing recorded them as red and after the merge every run looked
|
|
804
|
+
uncoloured. Uses `Manifold::OriginalID()` where the body is still one original, so the common case
|
|
805
|
+
costs no mesh build.
|
|
806
|
+
**An unknown run falls back to `nullopt`, never `cb.color`** — `cb.color` is the *first* child's
|
|
807
|
+
colour, so falling back to it made an uncoloured sibling look identically coloured, `allSame` came
|
|
808
|
+
out true, and nothing was tagged at all.
|
|
809
|
+
And the invariant behind both: **`triColors` must index the body's CURRENT mesh**. The renderer
|
|
810
|
+
masks its vertex arrays with it, so a stale length is an `IndexError` and a blank viewport rather
|
|
811
|
+
than a wrong colour. Anything that re-meshes clears it — `simplify()`, `minkowski_difference()`,
|
|
812
|
+
and the ID-retag rebuild when the triangle count moves — and `bodyToDict` drops a mismatched array
|
|
813
|
+
as a backstop for whichever one gets missed next.
|
|
814
|
+
**2D cannot use any of that, and keeps colour geometrically instead** (`Part2d`, same file): a
|
|
815
|
+
`CrossSection` is contours, not a mesh, so nothing in it remembers which child an edge came from
|
|
816
|
+
and there is no provenance for `attachTriColors` to read back. So the 2D accumulator holds **one
|
|
817
|
+
part per colour** rather than one merged section — same-coloured children still merge into one
|
|
818
|
+
part, a later statement notches what it covers out of the earlier parts (painter's order, the
|
|
819
|
+
rule `splitBodiesForExport` applies to overlapping 3D solids), `difference`/`intersection` apply
|
|
820
|
+
to every part, and a part cut away entirely is dropped. `generateCsg` then returns one
|
|
821
|
+
`ColoredBody` per surviving part, so **a 2D `union()` of differently-coloured children returns
|
|
822
|
+
several bodies where it used to return one**. Reported as a user bug: `union() { color("red")
|
|
823
|
+
square(10); color("blue") translate([12,0]) square(10); }` drew both squares red, where OpenSCAD
|
|
824
|
+
draws red and blue (verified by pixel-sampling both binaries' PNG output). `linear_extrude` of
|
|
825
|
+
such a union still drops colour entirely — checked against the real binary, which does the same.
|
|
796
826
|
- `src/builtins/primitives_3d.cpp` — `sphere(style=)` is a BelfrySCAD extension naming the
|
|
797
827
|
tessellation, using BOSL2's five `spheroid()` style names and constructions: `"orig"` (the default,
|
|
798
828
|
and what OpenSCAD's own sphere() builds — rings offset half a step from the poles, no pole vertex),
|
|
@@ -168,6 +168,13 @@ nb::dict bodyToDict(oscadeval::ColoredBody& cb) {
|
|
|
168
168
|
// (numTri, 4) float32 array or None). The renderer reads this to split
|
|
169
169
|
// one merged body's triangles across separate opaque/translucent draw
|
|
170
170
|
// buffers.
|
|
171
|
+
// Size-checked, not trusted: a per-triangle array that disagrees with
|
|
172
|
+
// the mesh it is meant to index makes the renderer raise IndexError and
|
|
173
|
+
// draw nothing. Dropping it costs the per-triangle colours of one body
|
|
174
|
+
// and keeps the model on screen. Everything that can invalidate it is
|
|
175
|
+
// supposed to clear it (simplify(), minkowski_difference(), the retag
|
|
176
|
+
// rebuild); this is the backstop for the one that gets missed.
|
|
177
|
+
if (cb.triColors && cb.triColors->size() != numTri) cb.triColors.reset();
|
|
171
178
|
if (cb.triColors) {
|
|
172
179
|
const std::vector<std::array<float, 4>>& src = *cb.triColors;
|
|
173
180
|
std::vector<float> flat;
|
|
@@ -1237,6 +1237,13 @@ public:
|
|
|
1237
1237
|
// it), which no RAII guard can span.
|
|
1238
1238
|
bool measuring_ = false;
|
|
1239
1239
|
|
|
1240
|
+
// True while a render() expression is measuring geometry it will then
|
|
1241
|
+
// discard. The provenance tables (idToNode/idToColor) are not written
|
|
1242
|
+
// during that, so anything outside this class applying the same guard
|
|
1243
|
+
// -- color.cpp records run colours the way tagGenerated does -- reads
|
|
1244
|
+
// it here.
|
|
1245
|
+
bool measuring() const { return measuring_; }
|
|
1246
|
+
|
|
1240
1247
|
// Test-only accessors for the invariants above -- a leaked measuring_ or
|
|
1241
1248
|
// an unbalanced treeStack_ is otherwise silent until something much
|
|
1242
1249
|
// later goes mysteriously wrong.
|
|
@@ -184,7 +184,13 @@ void attachTriColors(Evaluator& ev, ColoredBody& cb) {
|
|
|
184
184
|
perRunColor.reserve(runIds.size());
|
|
185
185
|
for (uint32_t rid : runIds) {
|
|
186
186
|
auto it = ev.idToColor.find(rid);
|
|
187
|
-
|
|
187
|
+
// nullopt, NOT cb.color, when a run has no recorded colour of its
|
|
188
|
+
// own. cb.color is the FIRST child's colour, so falling back to it
|
|
189
|
+
// made an uncoloured child look identically coloured, `allSame`
|
|
190
|
+
// came out true, and the whole merge kept one colour -- which is
|
|
191
|
+
// the "union() { color("red") a; b; } is all red" bug. nullopt is
|
|
192
|
+
// what an uncoloured body means everywhere else: follow the theme.
|
|
193
|
+
perRunColor.push_back(it != ev.idToColor.end() ? it->second : std::nullopt);
|
|
188
194
|
}
|
|
189
195
|
const bool allSame =
|
|
190
196
|
std::all_of(perRunColor.begin(), perRunColor.end(), [&](const auto& c) { return c == perRunColor.front(); });
|
|
@@ -201,6 +207,57 @@ void attachTriColors(Evaluator& ev, ColoredBody& cb) {
|
|
|
201
207
|
cb.triColors = std::move(triColors);
|
|
202
208
|
}
|
|
203
209
|
|
|
210
|
+
// One colour's worth of 2D result.
|
|
211
|
+
//
|
|
212
|
+
// 3D recovers per-child colour AFTER the merge, from Manifold's own
|
|
213
|
+
// per-triangle provenance (attachTriColors above). A CrossSection has no
|
|
214
|
+
// such thing -- it is contours, not a mesh, and nothing in it remembers
|
|
215
|
+
// which child a given edge came from. So 2D has to keep colour
|
|
216
|
+
// GEOMETRICALLY instead: one part per colour, each notched by whatever is
|
|
217
|
+
// drawn over it later. That is the same painter's-order rule
|
|
218
|
+
// splitBodiesForExport applies to overlapping 3D solids, and it is what
|
|
219
|
+
// `union() { color("red") square(10); color("blue") ... }` needs to come
|
|
220
|
+
// out as two coloured shapes instead of one shape wearing the first
|
|
221
|
+
// child's colour.
|
|
222
|
+
struct Part2d {
|
|
223
|
+
std::optional<std::array<float, 4>> color;
|
|
224
|
+
manifold::CrossSection section;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// Appends `add` to `parts`, merging into an existing part of the same
|
|
228
|
+
// colour so `union() { color("red") a; color("red") b; }` stays one body.
|
|
229
|
+
void addPart(std::vector<Part2d>& parts, const std::optional<std::array<float, 4>>& color,
|
|
230
|
+
const manifold::CrossSection& section) {
|
|
231
|
+
for (Part2d& p : parts) {
|
|
232
|
+
if (p.color == color) {
|
|
233
|
+
p.section = p.section + section;
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
parts.push_back({color, section});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// The 2D operands of one statement, grouped by colour.
|
|
241
|
+
std::vector<Part2d> partsOf(const std::vector<ColoredBody>& sections2d) {
|
|
242
|
+
std::vector<Part2d> parts;
|
|
243
|
+
for (const ColoredBody& c : sections2d) addPart(parts, c.color, *c.section);
|
|
244
|
+
return parts;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Every part's section unioned -- the shape the statement covers,
|
|
248
|
+
// whatever colours it is in.
|
|
249
|
+
manifold::CrossSection coveredBy(const std::vector<Part2d>& parts) {
|
|
250
|
+
manifold::CrossSection all;
|
|
251
|
+
for (const Part2d& p : parts) all = all + p.section;
|
|
252
|
+
return all;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
void dropEmptyParts(std::vector<Part2d>& parts) {
|
|
256
|
+
parts.erase(std::remove_if(parts.begin(), parts.end(),
|
|
257
|
+
[](const Part2d& p) { return p.section.IsEmpty(); }),
|
|
258
|
+
parts.end());
|
|
259
|
+
}
|
|
260
|
+
|
|
204
261
|
} // namespace
|
|
205
262
|
|
|
206
263
|
std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, const std::vector<std::unique_ptr<CSGNode>>& children,
|
|
@@ -222,7 +279,12 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
222
279
|
// part-way. difference and intersection still see one dimension only:
|
|
223
280
|
// applyDimensionRules drops the mismatch before it gets here, so for
|
|
224
281
|
// them just one of these is ever populated.
|
|
225
|
-
std::optional<ColoredBody> res3d
|
|
282
|
+
std::optional<ColoredBody> res3d;
|
|
283
|
+
// 2D keeps one entry per colour rather than one merged section; see
|
|
284
|
+
// Part2d. `have2d` distinguishes "no 2D operand yet" from "every 2D
|
|
285
|
+
// part has been cut away", which matters to difference().
|
|
286
|
+
std::vector<Part2d> res2d;
|
|
287
|
+
bool have2d = false;
|
|
226
288
|
size_t idx = 0;
|
|
227
289
|
|
|
228
290
|
size_t stmtIndex = 0;
|
|
@@ -282,10 +344,11 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
282
344
|
// union just skips the empty contributor and keeps going.
|
|
283
345
|
if (op == "intersection") {
|
|
284
346
|
res3d.reset();
|
|
285
|
-
res2d.
|
|
347
|
+
res2d.clear();
|
|
348
|
+
have2d = false;
|
|
286
349
|
break;
|
|
287
350
|
}
|
|
288
|
-
if (op == "difference" && !res3d && !
|
|
351
|
+
if (op == "difference" && !res3d && !have2d) break;
|
|
289
352
|
continue;
|
|
290
353
|
}
|
|
291
354
|
|
|
@@ -309,20 +372,25 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
309
372
|
}
|
|
310
373
|
}
|
|
311
374
|
if (!sections2d.empty()) {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (!
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
cb.color = sections2d.front().color;
|
|
318
|
-
res2d = std::move(cb);
|
|
375
|
+
std::vector<Part2d> stmtParts = partsOf(sections2d);
|
|
376
|
+
const manifold::CrossSection grp = coveredBy(stmtParts);
|
|
377
|
+
if (!have2d) {
|
|
378
|
+
res2d = std::move(stmtParts);
|
|
379
|
+
have2d = true;
|
|
319
380
|
} else if (op == "union") {
|
|
320
|
-
|
|
381
|
+
// Later wins the overlap: notch what is already there by
|
|
382
|
+
// everything this statement covers, then add this
|
|
383
|
+
// statement's parts. Same rule as two overlapping 3D
|
|
384
|
+
// solids of different colours, and the same thing a
|
|
385
|
+
// painter does.
|
|
386
|
+
for (Part2d& p : res2d) p.section = p.section - grp;
|
|
387
|
+
for (Part2d& np : stmtParts) addPart(res2d, np.color, np.section);
|
|
321
388
|
} else if (op == "difference") {
|
|
322
|
-
res2d
|
|
389
|
+
for (Part2d& p : res2d) p.section = p.section - grp;
|
|
323
390
|
} else if (op == "intersection") {
|
|
324
|
-
res2d
|
|
391
|
+
for (Part2d& p : res2d) p.section = p.section ^ grp;
|
|
325
392
|
}
|
|
393
|
+
dropEmptyParts(res2d);
|
|
326
394
|
}
|
|
327
395
|
}
|
|
328
396
|
|
|
@@ -330,7 +398,12 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
330
398
|
|
|
331
399
|
std::vector<ColoredBody> result;
|
|
332
400
|
if (res3d) result.push_back(std::move(*res3d));
|
|
333
|
-
|
|
401
|
+
for (Part2d& p : res2d) {
|
|
402
|
+
ColoredBody cb;
|
|
403
|
+
cb.color = p.color;
|
|
404
|
+
cb.section = std::move(p.section);
|
|
405
|
+
result.push_back(std::move(cb));
|
|
406
|
+
}
|
|
334
407
|
result.insert(result.end(), allBg.begin(), allBg.end());
|
|
335
408
|
result.insert(result.end(), allHi.begin(), allHi.end());
|
|
336
409
|
result.insert(result.end(), allSo.begin(), allSo.end());
|
|
@@ -50,12 +50,42 @@ CSGParams resolveColor(Evaluator& ev, const oscad::ModularCall& node, EvalContex
|
|
|
50
50
|
return std::move(result.params);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
namespace {
|
|
54
|
+
|
|
55
|
+
// Stamping cb.color is not enough: the colour has to be recorded against
|
|
56
|
+
// the body's RUN IDS too.
|
|
57
|
+
//
|
|
58
|
+
// attachTriColors (booleans.cpp) reads `idToColor` back AFTER a merge has
|
|
59
|
+
// thrown the individual bodies away -- run IDs are all it has left to go
|
|
60
|
+
// on -- and a run it cannot find looks uncoloured. tagGenerated() records
|
|
61
|
+
// the colour a body was BORN with, which covers `color("red") cube(10)`
|
|
62
|
+
// because the colour reaches the primitive through the context. It does
|
|
63
|
+
// not cover a body that already existed when colour was applied to it,
|
|
64
|
+
// which is every module whose geometry comes out of its own CSG:
|
|
65
|
+
// `union() { color("red") stroke(...); text(); }` had no red recorded for
|
|
66
|
+
// the stroke's runs at all, so every run looked identical, the merge kept
|
|
67
|
+
// the first child's colour, and the whole thing came out red.
|
|
68
|
+
void recordRunColors(Evaluator& ev, const ColoredBody& b, const std::optional<std::array<float, 4>>& rgba) {
|
|
69
|
+
if (!b.body || b.body->IsEmpty()) return;
|
|
70
|
+
// A body that is still one original knows its own ID without building
|
|
71
|
+
// a mesh -- the common case, and the cheap one.
|
|
72
|
+
const int original = b.body->OriginalID();
|
|
73
|
+
if (original >= 0) {
|
|
74
|
+
ev.idToColor[static_cast<uint32_t>(original)] = rgba;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
for (uint32_t id : b.body->GetMeshGL().runOriginalID) ev.idToColor[id] = rgba;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
} // namespace
|
|
81
|
+
|
|
82
|
+
std::vector<ColoredBody> generateColor(Evaluator& ev, const CSGParams& params,
|
|
54
83
|
const std::vector<std::unique_ptr<CSGNode>>& children, const oscad::ASTNode&) {
|
|
55
84
|
const auto rgba = valueToColor(params.at("rgba"));
|
|
56
85
|
std::vector<ColoredBody> result;
|
|
57
86
|
for (ColoredBody b : flattenCsgTree(children)) {
|
|
58
87
|
b.color = rgba;
|
|
88
|
+
if (!ev.measuring()) recordRunColors(ev, b, rgba);
|
|
59
89
|
result.push_back(std::move(b));
|
|
60
90
|
}
|
|
61
91
|
return result;
|
|
@@ -481,7 +481,14 @@ std::vector<ColoredBody> generateSimplify(Evaluator& ev, const CSGParams& params
|
|
|
481
481
|
const manifold::vec3 d = bb.Size();
|
|
482
482
|
tol = kDefaultSimplifyFraction * std::sqrt(d.x * d.x + d.y * d.y + d.z * d.z);
|
|
483
483
|
}
|
|
484
|
-
if (tol > 0.0)
|
|
484
|
+
if (tol > 0.0) {
|
|
485
|
+
cb.body = b.body->Simplify(tol);
|
|
486
|
+
// triColors is indexed by triangle, and decimation changes
|
|
487
|
+
// how many there are -- carrying it across leaves the
|
|
488
|
+
// renderer masking a 550-triangle mesh with a 556-entry
|
|
489
|
+
// array, which is an IndexError, not a wrong colour.
|
|
490
|
+
cb.triColors.reset();
|
|
491
|
+
}
|
|
485
492
|
} else if (b.section) {
|
|
486
493
|
double tol = explicitValue;
|
|
487
494
|
if (!explicitTol) {
|
|
@@ -331,7 +331,16 @@ void Evaluator::restampCachedIds(std::vector<ColoredBody>& bodies, const oscad::
|
|
|
331
331
|
}
|
|
332
332
|
id = found->second;
|
|
333
333
|
}
|
|
334
|
+
const size_t trisBefore = mesh.triVerts.size() / 3;
|
|
334
335
|
cb.body = manifold::Manifold(mesh);
|
|
336
|
+
// Rebuilding a Manifold from a mesh can clean it up (degenerate
|
|
337
|
+
// triangles merged away), and triColors is indexed by triangle. An
|
|
338
|
+
// array that no longer matches is worse than none: the renderer
|
|
339
|
+
// masks its vertex arrays with it and raises IndexError rather
|
|
340
|
+
// than drawing anything at all.
|
|
341
|
+
if (cb.triColors && cb.body && cb.body->GetMeshGL().triVerts.size() / 3 != trisBefore) {
|
|
342
|
+
cb.triColors.reset();
|
|
343
|
+
}
|
|
335
344
|
}
|
|
336
345
|
}
|
|
337
346
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
#include <algorithm>
|
|
8
8
|
#include <gtest/gtest.h>
|
|
9
|
+
#include <set>
|
|
9
10
|
|
|
10
11
|
using namespace oscadeval;
|
|
11
12
|
using namespace oscadeval::test;
|
|
@@ -1439,3 +1440,196 @@ TEST(LevelSet, AGridFieldIsAlsoCutCleanlyAtTheBox) {
|
|
|
1439
1440
|
ASSERT_EQ(e.bodies.size(), 1u);
|
|
1440
1441
|
EXPECT_NEAR(soleBody(e).Volume(), 32000.0, 40.0); // one sample layer of slack
|
|
1441
1442
|
}
|
|
1443
|
+
|
|
1444
|
+
// -- 2D union keeps every colour (bug report: "multiple colors inside a
|
|
1445
|
+
// union(), only one color is used") -----------------------------------
|
|
1446
|
+
|
|
1447
|
+
namespace {
|
|
1448
|
+
|
|
1449
|
+
// (colour, area) per 2D body, in result order.
|
|
1450
|
+
std::vector<std::pair<std::array<float, 4>, double>> colouredAreas(const std::vector<ColoredBody>& bodies) {
|
|
1451
|
+
std::vector<std::pair<std::array<float, 4>, double>> out;
|
|
1452
|
+
for (const ColoredBody& b : bodies) {
|
|
1453
|
+
if (!b.section) continue;
|
|
1454
|
+
out.emplace_back(b.color.value_or(std::array<float, 4>{0, 0, 0, 0}), b.section->Area());
|
|
1455
|
+
}
|
|
1456
|
+
return out;
|
|
1457
|
+
}
|
|
1458
|
+
|
|
1459
|
+
constexpr std::array<float, 4> kRed{1, 0, 0, 1};
|
|
1460
|
+
constexpr std::array<float, 4> kBlue{0, 0, 1, 1};
|
|
1461
|
+
|
|
1462
|
+
} // namespace
|
|
1463
|
+
|
|
1464
|
+
TEST(Union2dColor, KeepsOneBodyPerColour) {
|
|
1465
|
+
// A CrossSection has no per-edge provenance for attachTriColors to read
|
|
1466
|
+
// back afterwards, so 2D keeps colour by staying in separate parts.
|
|
1467
|
+
// Before this, both squares came out red -- the first child's colour
|
|
1468
|
+
// for the whole merged section, where OpenSCAD draws red AND blue.
|
|
1469
|
+
Evaluated e = evalSrc("union() { color(\"red\") square(10); color(\"blue\") translate([12,0]) square(10); }");
|
|
1470
|
+
const auto parts = colouredAreas(e.bodies);
|
|
1471
|
+
ASSERT_EQ(parts.size(), 2u);
|
|
1472
|
+
EXPECT_EQ(parts[0].first, kRed);
|
|
1473
|
+
EXPECT_EQ(parts[1].first, kBlue);
|
|
1474
|
+
EXPECT_NEAR(parts[0].second, 100.0, 1e-6);
|
|
1475
|
+
EXPECT_NEAR(parts[1].second, 100.0, 1e-6);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
TEST(Union2dColor, OneColourStaysOneBody) {
|
|
1479
|
+
// Splitting per colour must not split per child: two red squares are
|
|
1480
|
+
// one red shape, as they always were.
|
|
1481
|
+
Evaluated e = evalSrc("union() { color(\"red\") square(10); color(\"red\") translate([12,0]) square(10); }");
|
|
1482
|
+
const auto parts = colouredAreas(e.bodies);
|
|
1483
|
+
ASSERT_EQ(parts.size(), 1u);
|
|
1484
|
+
EXPECT_EQ(parts[0].first, kRed);
|
|
1485
|
+
EXPECT_NEAR(parts[0].second, 200.0, 1e-6);
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
TEST(Union2dColor, AnUncolouredUnionIsStillASingleBody) {
|
|
1489
|
+
Evaluated e = evalSrc("union() { square(10); translate([12,0]) square(10); }");
|
|
1490
|
+
ASSERT_EQ(e.bodies.size(), 1u);
|
|
1491
|
+
ASSERT_TRUE(e.bodies[0].section.has_value());
|
|
1492
|
+
EXPECT_FALSE(e.bodies[0].color.has_value());
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
TEST(Union2dColor, TheLaterColourWinsAnOverlap) {
|
|
1496
|
+
// Painter's order, the same rule splitBodiesForExport applies to
|
|
1497
|
+
// overlapping 3D solids -- and what OpenSCAD's own preview shows.
|
|
1498
|
+
Evaluated e = evalSrc(
|
|
1499
|
+
"union() { color(\"red\") square(10); color(\"blue\") translate([5,5]) square(10); }");
|
|
1500
|
+
const auto parts = colouredAreas(e.bodies);
|
|
1501
|
+
ASSERT_EQ(parts.size(), 2u);
|
|
1502
|
+
EXPECT_EQ(parts[0].first, kRed);
|
|
1503
|
+
EXPECT_EQ(parts[1].first, kBlue);
|
|
1504
|
+
// Blue keeps its whole square; red is notched by the 5x5 overlap.
|
|
1505
|
+
EXPECT_NEAR(parts[1].second, 100.0, 1e-6);
|
|
1506
|
+
EXPECT_NEAR(parts[0].second, 75.0, 1e-6);
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
TEST(Union2dColor, DifferenceCutsEveryColouredPart) {
|
|
1510
|
+
Evaluated e = evalSrc(
|
|
1511
|
+
"difference() {"
|
|
1512
|
+
" union() { color(\"red\") square(10); color(\"blue\") translate([10,0]) square(10); }"
|
|
1513
|
+
" translate([5,0]) square(10);"
|
|
1514
|
+
"}");
|
|
1515
|
+
const auto parts = colouredAreas(e.bodies);
|
|
1516
|
+
ASSERT_EQ(parts.size(), 2u);
|
|
1517
|
+
// The cut spans both: 5 wide off red's right, 5 off blue's left.
|
|
1518
|
+
EXPECT_NEAR(parts[0].second, 50.0, 1e-6);
|
|
1519
|
+
EXPECT_NEAR(parts[1].second, 50.0, 1e-6);
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
TEST(Union2dColor, IntersectionKeepsColoursToo) {
|
|
1523
|
+
Evaluated e = evalSrc(
|
|
1524
|
+
"intersection() {"
|
|
1525
|
+
" union() { color(\"red\") square(10); color(\"blue\") translate([10,0]) square(10); }"
|
|
1526
|
+
" translate([5,0]) square(10);"
|
|
1527
|
+
"}");
|
|
1528
|
+
const auto parts = colouredAreas(e.bodies);
|
|
1529
|
+
ASSERT_EQ(parts.size(), 2u);
|
|
1530
|
+
EXPECT_EQ(parts[0].first, kRed);
|
|
1531
|
+
EXPECT_EQ(parts[1].first, kBlue);
|
|
1532
|
+
EXPECT_NEAR(parts[0].second, 50.0, 1e-6);
|
|
1533
|
+
EXPECT_NEAR(parts[1].second, 50.0, 1e-6);
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
TEST(Union2dColor, APartCutAwayEntirelyIsDropped) {
|
|
1537
|
+
Evaluated e = evalSrc(
|
|
1538
|
+
"difference() {"
|
|
1539
|
+
" union() { color(\"red\") square(10); color(\"blue\") translate([20,0]) square(10); }"
|
|
1540
|
+
" square(10);"
|
|
1541
|
+
"}");
|
|
1542
|
+
const auto parts = colouredAreas(e.bodies);
|
|
1543
|
+
ASSERT_EQ(parts.size(), 1u);
|
|
1544
|
+
EXPECT_EQ(parts[0].first, kBlue);
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
TEST(Union2dColor, ExtrudingAColouredUnionStillDropsColour) {
|
|
1548
|
+
// Not a bug, and checked against the real binary: OpenSCAD's own
|
|
1549
|
+
// linear_extrude of coloured 2D children draws the default colour too.
|
|
1550
|
+
// Splitting 2D by colour must not accidentally start colouring these.
|
|
1551
|
+
Evaluated e = evalSrc(
|
|
1552
|
+
"linear_extrude(5) union() { color(\"red\") square(10); color(\"blue\") translate([12,0]) square(10); }");
|
|
1553
|
+
ASSERT_EQ(e.bodies.size(), 1u);
|
|
1554
|
+
ASSERT_TRUE(e.bodies[0].body.has_value());
|
|
1555
|
+
EXPECT_FALSE(e.bodies[0].color.has_value());
|
|
1556
|
+
EXPECT_NEAR(e.bodies[0].body->Volume(), 1000.0, 1e-6);
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
|
|
1560
|
+
// -- 3D colour survives a merge (BelfrySCAD #372) -------------------------
|
|
1561
|
+
|
|
1562
|
+
namespace {
|
|
1563
|
+
|
|
1564
|
+
std::set<std::array<float, 4>> distinctTriColors(const ColoredBody& b) {
|
|
1565
|
+
std::set<std::array<float, 4>> out;
|
|
1566
|
+
if (b.triColors) out.insert(b.triColors->begin(), b.triColors->end());
|
|
1567
|
+
return out;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
} // namespace
|
|
1571
|
+
|
|
1572
|
+
TEST(Union3dColor, ColourAppliedToForwardedChildrenSurvivesTheMerge) {
|
|
1573
|
+
// The reported case, reduced out of BOSL2. Its stroke() colours what
|
|
1574
|
+
// it draws through exactly this shape -- a module that wraps FORWARDED
|
|
1575
|
+
// children in color(). The children were generated in the caller's
|
|
1576
|
+
// context, where there is no colour, so tagGenerated() recorded them as
|
|
1577
|
+
// uncoloured; color() then stamped cb.color and nothing else. After the
|
|
1578
|
+
// merge, attachTriColors had only run IDs to go on, every one of them
|
|
1579
|
+
// looked uncoloured, they all "matched", and the union kept the first
|
|
1580
|
+
// child's colour -- the whole model came out red.
|
|
1581
|
+
Evaluated e = evalSrc(
|
|
1582
|
+
"module setcolor(clr) { color(clr) children(); }\n"
|
|
1583
|
+
"union() {"
|
|
1584
|
+
" setcolor(\"red\") cube(10);"
|
|
1585
|
+
" translate([12,0,0]) cube(10);"
|
|
1586
|
+
"}");
|
|
1587
|
+
ASSERT_EQ(e.bodies.size(), 1u);
|
|
1588
|
+
ASSERT_TRUE(e.bodies[0].triColors.has_value());
|
|
1589
|
+
const auto colours = distinctTriColors(e.bodies[0]);
|
|
1590
|
+
EXPECT_EQ(colours.size(), 2u);
|
|
1591
|
+
EXPECT_EQ(colours.count(std::array<float, 4>{1, 0, 0, 1}), 1u);
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
TEST(Union3dColor, AnUncolouredChildDoesNotInheritTheColouredOne) {
|
|
1595
|
+
// perRunColor's fallback used to be cb.color -- the FIRST child's
|
|
1596
|
+
// colour -- so an uncoloured sibling looked identically coloured, the
|
|
1597
|
+
// "do the colours differ?" test said no, and nothing was tagged at all.
|
|
1598
|
+
Evaluated e = evalSrc(
|
|
1599
|
+
"union() { color(\"red\") cube(10); translate([12,0,0]) cube(10); }");
|
|
1600
|
+
ASSERT_EQ(e.bodies.size(), 1u);
|
|
1601
|
+
ASSERT_TRUE(e.bodies[0].triColors.has_value());
|
|
1602
|
+
const auto colours = distinctTriColors(e.bodies[0]);
|
|
1603
|
+
EXPECT_EQ(colours.size(), 2u);
|
|
1604
|
+
EXPECT_EQ(colours.count(std::array<float, 4>{1, 0, 0, 1}), 1u);
|
|
1605
|
+
// ... and the other half is the default, not red.
|
|
1606
|
+
for (const auto& c : colours) {
|
|
1607
|
+
if (c != std::array<float, 4>{1, 0, 0, 1}) EXPECT_NE(c[0], 1.0f);
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
TEST(Union3dColor, EveryTriangleIsAccountedFor) {
|
|
1612
|
+
// triColors must index the body's CURRENT mesh exactly: the renderer
|
|
1613
|
+
// masks its vertex arrays with it, so a stale length is an IndexError
|
|
1614
|
+
// and a blank viewport, not a wrong colour.
|
|
1615
|
+
Evaluated e = evalSrc(
|
|
1616
|
+
"union() { color(\"red\") cube(10); color(\"blue\") translate([12,0,0]) cube(10); }");
|
|
1617
|
+
ASSERT_EQ(e.bodies.size(), 1u);
|
|
1618
|
+
ASSERT_TRUE(e.bodies[0].triColors.has_value());
|
|
1619
|
+
EXPECT_EQ(e.bodies[0].triColors->size(), e.bodies[0].body->GetMeshGL().triVerts.size() / 3);
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
TEST(Union3dColor, SimplifyDropsPerTriangleColoursRatherThanKeepingStaleOnes) {
|
|
1623
|
+
// Decimation changes the triangle count; an array indexed against the
|
|
1624
|
+
// old one cannot be salvaged, and handing it on crashes the renderer.
|
|
1625
|
+
Evaluated e = evalSrc(
|
|
1626
|
+
"simplify(0.5) union() {"
|
|
1627
|
+
" color(\"red\") sphere(10, $fn=32);"
|
|
1628
|
+
" color(\"blue\") translate([25,0,0]) sphere(10, $fn=32);"
|
|
1629
|
+
"}");
|
|
1630
|
+
ASSERT_FALSE(e.bodies.empty());
|
|
1631
|
+
for (const ColoredBody& b : e.bodies) {
|
|
1632
|
+
if (!b.body || !b.triColors) continue;
|
|
1633
|
+
EXPECT_EQ(b.triColors->size(), b.body->GetMeshGL().triVerts.size() / 3);
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
File without changes
|
{openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/.github/workflows/wheels.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/examples/manifold_cache_reuse.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-1.11.0 → openscad_cpp_evaluator-1.13.0}/examples/minimal_debugger.cpp
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|