openscad-cpp-evaluator 0.55.3__tar.gz → 0.55.5__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-0.55.3 → openscad_cpp_evaluator-0.55.5}/CLAUDE.md +25 -8
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/bytecode.hpp +6 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/bytecode_vm.hpp +3 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/colored_body.hpp +17 -10
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/python/openscad_cpp_evaluator/__init__.py +2 -1
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/booleans.cpp +47 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/transforms.cpp +156 -5
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/bytecode_compiler.cpp +23 -7
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/bytecode_vm.cpp +12 -1
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/colored_body.cpp +4 -4
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/stmt_eval.cpp +10 -2
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_booleans.cpp +181 -20
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_control_flow.cpp +39 -6
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/README.md +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.55.3 → openscad_cpp_evaluator-0.55.5}/uv.lock +0 -0
|
@@ -231,14 +231,31 @@ top-level 2D primitive/projection() script had been silently unexportable via th
|
|
|
231
231
|
Fixed by porting `toRenderableBodies()` (`colored_body.hpp`/`.cpp`) and calling it from the CLI right
|
|
232
232
|
before export, matching the reference's own call site exactly.
|
|
233
233
|
|
|
234
|
-
`ColoredBody::
|
|
235
|
-
2D, so `down(1) square(10)` had nowhere to put the `-1` and
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
234
|
+
`ColoredBody::sectionXform` rides alongside for the same reason. A `manifold::CrossSection` is
|
|
235
|
+
purely 2D, so `down(1) square(10)` had nowhere to put the `-1` and `rotate([55,0,25]) text("Foo")`
|
|
236
|
+
had nowhere to put the rotation — both were silently dropped, and neither is cosmetic: BOSL2 layers
|
|
237
|
+
2D overlays by pushing one down (isosurface's `contour()` Example 1 puts a blue backdrop below a
|
|
238
|
+
green contour, and the two slabs became exactly coplanar and z-fought), and turns 2D labels to face
|
|
239
|
+
the camera with `rotate($vpr)` (skin's style figure, which came out lying flat and reading as a blob
|
|
240
|
+
once the preview slab became a full unit tall). `generateTransform` accumulates whatever the
|
|
241
|
+
CrossSection cannot hold into that matrix and `toRenderableBodies()` applies it to the extruded
|
|
242
|
+
slab.
|
|
243
|
+
|
|
244
|
+
Two rules keep the ordering honest. A transform the CrossSection *can* hold still goes into it, so
|
|
245
|
+
2D booleans and `offset()` keep operating on real 2D geometry — but only while the carried matrix is
|
|
246
|
+
still identity, since applying an outer transform to the section after an out-of-plane one would
|
|
247
|
+
silently reorder them. A pure `translate` is the one exception: while nothing has yet rotated or
|
|
248
|
+
scaled the section, its x/y goes into the section and only its z rides along, because translations
|
|
249
|
+
commute and that keeps `down(1) square(10)` a real 2D shape. `resize()` is carried by neither — the
|
|
250
|
+
reference passes 2D children through it unchanged.
|
|
251
|
+
|
|
252
|
+
The same "geometry Manifold cannot hold" problem applies to `ColoredBody::rawMesh`, the raw triangles
|
|
253
|
+
of a mesh Manifold rejected (an open surface — a height field, a partial `vnf_vertex_array`). Those
|
|
254
|
+
were left where they were built, so `grid_copies(...) vnf_polyhedron(<open surface>)` stacked every
|
|
255
|
+
copy at the origin and BOSL2's skin() style figure showed one shape where the reference shows seven.
|
|
256
|
+
`transformMatrix3d` (transforms.cpp) gives the affine matrix for a transform and
|
|
257
|
+
`generateTransform` applies it to those vertices too; `resize` returns nullopt there, being a
|
|
258
|
+
function of a bounding box a display-only body does not have.
|
|
242
259
|
|
|
243
260
|
**Font support**: a `FontProvider` abstract interface (`font_provider.hpp`: `resolveFont`/
|
|
244
261
|
`metrics`/`shapeText`/`glyphInkBounds`/`glyphOutline`) with `FreetypeFontProvider` as the built-in
|
|
@@ -15,6 +15,7 @@ class FunctionLiteral;
|
|
|
15
15
|
class ModuleDeclaration;
|
|
16
16
|
class ModularCall;
|
|
17
17
|
class ModularAssert;
|
|
18
|
+
class ModularEcho;
|
|
18
19
|
class Expression;
|
|
19
20
|
} // namespace oscad
|
|
20
21
|
|
|
@@ -868,6 +869,11 @@ struct CompiledChunk {
|
|
|
868
869
|
// unused and misleadingly defaulted.
|
|
869
870
|
struct EchoSite {
|
|
870
871
|
std::vector<std::optional<std::string>> argNames;
|
|
872
|
+
// The ModularEcho statement, when this site came from one -- an
|
|
873
|
+
// `echo(...) cube();` renders its child after echoing, exactly as
|
|
874
|
+
// AssertSite::node does for `assert(...) cube();`. Null for the
|
|
875
|
+
// EXPRESSION form (`echo(...) 1+1`), which has no children.
|
|
876
|
+
const oscad::ModularEcho* node = nullptr;
|
|
871
877
|
};
|
|
872
878
|
|
|
873
879
|
// One Op::CallModule site -- a ModularCall statically resolved (at
|
|
@@ -68,6 +68,9 @@ struct PendingCsgWrap {
|
|
|
68
68
|
std::uint64_t randsBefore = 0;
|
|
69
69
|
int siteIdx = -1;
|
|
70
70
|
std::vector<Value> groupSizes;
|
|
71
|
+
// Parallel to groupSizes: whether a group that came out EMPTY is still
|
|
72
|
+
// an operand. See Op::CsgGroupEnd's `a`.
|
|
73
|
+
std::vector<Value> emptyIsAGroup;
|
|
71
74
|
size_t groupStartSize = 0;
|
|
72
75
|
};
|
|
73
76
|
|
|
@@ -25,20 +25,27 @@ struct ColoredBody {
|
|
|
25
25
|
std::optional<manifold::CrossSection> section;
|
|
26
26
|
bool flatPreview = false;
|
|
27
27
|
|
|
28
|
-
//
|
|
29
|
-
//
|
|
28
|
+
// What a 2D `section` has been transformed BY that a CrossSection
|
|
29
|
+
// cannot itself hold: a translation along Z, a rotation out of the XY
|
|
30
|
+
// plane, anything with a Z component. Applied when
|
|
31
|
+
// toRenderableBodies() extrudes the section.
|
|
30
32
|
//
|
|
31
33
|
// A manifold::CrossSection is purely 2D, so `down(1) square(10)` had
|
|
32
|
-
// nowhere to put the -1 and
|
|
34
|
+
// nowhere to put the -1 and `rotate([55,0,25]) text("Foo")` had nowhere
|
|
35
|
+
// to put the rotation -- both were silently dropped. Neither is
|
|
33
36
|
// cosmetic: BOSL2 layers 2D overlays by pushing one down (isosurface's
|
|
34
|
-
// contour() Example 1
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
+
// contour() Example 1), and turns 2D labels to face the camera with
|
|
38
|
+
// `rotate($vpr)` (skin's style figure), which came out lying flat and
|
|
39
|
+
// read as a blob once the preview slab became a full unit tall.
|
|
37
40
|
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
41
|
-
|
|
41
|
+
// Identity while every transform so far has been 2D-representable --
|
|
42
|
+
// those still go into the CrossSection itself, so 2D booleans and
|
|
43
|
+
// offset() keep working on real 2D geometry. From the first transform
|
|
44
|
+
// that is NOT representable, every later one composes here instead:
|
|
45
|
+
// applying an outer transform to the section after an out-of-plane one
|
|
46
|
+
// would put it in the wrong order.
|
|
47
|
+
manifold::mat3x4 sectionXform{manifold::vec3(1, 0, 0), manifold::vec3(0, 1, 0),
|
|
48
|
+
manifold::vec3(0, 0, 1), manifold::vec3(0, 0, 0)};
|
|
42
49
|
BodyRole role = BodyRole::Normal;
|
|
43
50
|
std::optional<std::vector<std::array<float, 4>>> triColors; // per-triangle RGBA, multi-color CSG merges only
|
|
44
51
|
|
|
@@ -213,7 +213,8 @@ def _summarize_param(value, max_items: int = 6, max_len: int = 40) -> str:
|
|
|
213
213
|
# Params keys never shown in format_csg_tree's per-node summary, regardless
|
|
214
214
|
# of kind -- pure internal bookkeeping or already represented structurally
|
|
215
215
|
# elsewhere in the tree. Mirrors the reference's _DUMP_HIDDEN_PARAM_KEYS.
|
|
216
|
-
_DUMP_HIDDEN_PARAM_KEYS = frozenset(
|
|
216
|
+
_DUMP_HIDDEN_PARAM_KEYS = frozenset(
|
|
217
|
+
{"color", "op", "name", "group_sizes", "empty_is_a_group"})
|
|
217
218
|
|
|
218
219
|
# Auto-generated tessellation data (not user-authored) for every kind except
|
|
219
220
|
# polyhedron, where the equivalent data *is* the user's own points/faces.
|
|
@@ -108,16 +108,43 @@ CSGParams resolveCsg(Evaluator& ev, const oscad::ModularCall& node, EvalContext&
|
|
|
108
108
|
if (!assignNodes.empty()) ev.evalChildren(assignNodes, blockCtx);
|
|
109
109
|
|
|
110
110
|
std::vector<Value> groupSizes;
|
|
111
|
+
std::vector<Value> emptyIsAGroup;
|
|
111
112
|
groupSizes.reserve(geoNodes.size());
|
|
113
|
+
emptyIsAGroup.reserve(geoNodes.size());
|
|
112
114
|
for (const oscad::ASTNode* geoNode : geoNodes) {
|
|
113
115
|
const size_t before = ev.currentTreeFrameSize();
|
|
114
116
|
ev.evalChildren(std::vector<const oscad::ASTNode*>{geoNode}, blockCtx);
|
|
115
117
|
groupSizes.push_back(Value{static_cast<double>(ev.currentTreeFrameSize() - before)});
|
|
118
|
+
// Whether a statement that produced NOTHING still counts as an
|
|
119
|
+
// operand.
|
|
120
|
+
//
|
|
121
|
+
// The reference builds a node for a module instantiation and for a
|
|
122
|
+
// loop whatever they contain, so an empty one is an empty operand
|
|
123
|
+
// and annihilates an intersection. An `if` that takes no branch, a
|
|
124
|
+
// bare block, and a `*`-disabled statement build no node at all, so
|
|
125
|
+
// they are not operands and must be skipped.
|
|
126
|
+
//
|
|
127
|
+
// Every line of this was checked against OpenSCAD rather than
|
|
128
|
+
// reasoned about -- `intersection(){ cube(10); X; }` keeps the cube
|
|
129
|
+
// for `if(false) sphere(6)`, `{ }` and `*cube(1)`, and comes out
|
|
130
|
+
// empty for `for(i=[1:0]) sphere(6)`, `union(){}`, `group(){}` and
|
|
131
|
+
// a call to an empty user module.
|
|
132
|
+
const oscad::NodeKind k = geoNode->kind();
|
|
133
|
+
emptyIsAGroup.push_back(Value{
|
|
134
|
+
k == oscad::NodeKind::ModularCall ||
|
|
135
|
+
k == oscad::NodeKind::ModularFor ||
|
|
136
|
+
k == oscad::NodeKind::ModularIntersectionFor ||
|
|
137
|
+
k == oscad::NodeKind::ModularLet ||
|
|
138
|
+
k == oscad::NodeKind::ModularModifierShowOnly ||
|
|
139
|
+
k == oscad::NodeKind::ModularModifierHighlight ||
|
|
140
|
+
k == oscad::NodeKind::ModularModifierBackground});
|
|
116
141
|
}
|
|
117
142
|
|
|
118
143
|
CSGParams params;
|
|
119
144
|
params["op"] = Value{op};
|
|
120
145
|
params["group_sizes"] = Value{std::make_shared<const ValueList>(ValueList{std::move(groupSizes)})};
|
|
146
|
+
params["empty_is_a_group"] =
|
|
147
|
+
Value{std::make_shared<const ValueList>(ValueList{std::move(emptyIsAGroup)})};
|
|
121
148
|
return params;
|
|
122
149
|
}
|
|
123
150
|
|
|
@@ -180,16 +207,36 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
180
207
|
const oscad::ASTNode&) {
|
|
181
208
|
const std::string& op = std::get<std::string>(params.at("op"));
|
|
182
209
|
const auto& groupSizes = std::get<ListPtr>(params.at("group_sizes"))->items;
|
|
210
|
+
const auto emptyIsAGroupIt = params.find("empty_is_a_group");
|
|
211
|
+
const std::vector<Value>* emptyIsAGroup =
|
|
212
|
+
emptyIsAGroupIt == params.end()
|
|
213
|
+
? nullptr
|
|
214
|
+
: &std::get<ListPtr>(emptyIsAGroupIt->second)->items;
|
|
183
215
|
|
|
184
216
|
std::vector<ColoredBody> allBg, allHi, allSo, allDo;
|
|
185
217
|
std::optional<ColoredBody> csgResult;
|
|
186
218
|
size_t idx = 0;
|
|
187
219
|
|
|
220
|
+
size_t stmtIndex = 0;
|
|
188
221
|
for (const Value& sizeVal : groupSizes) {
|
|
189
222
|
const size_t size = static_cast<size_t>(std::get<double>(sizeVal));
|
|
223
|
+
const size_t thisStmt = stmtIndex++;
|
|
190
224
|
std::vector<ColoredBody> stmtBodies = flattenCsgTree(children, idx, size);
|
|
191
225
|
idx += size;
|
|
192
226
|
|
|
227
|
+
// A statement that built no CSG node at all is not an operand --
|
|
228
|
+
// an `if` whose branch was not taken, or an empty block. Only a
|
|
229
|
+
// for-loop still counts as one when it produced nothing, matching
|
|
230
|
+
// the group node the reference builds for it regardless. Without
|
|
231
|
+
// this, `intersection(){ X; if (crop) Y; }` -- BOSL2's hirth()
|
|
232
|
+
// among others -- came out empty whenever the condition was false.
|
|
233
|
+
if (size == 0) {
|
|
234
|
+
const bool isGroup = emptyIsAGroup && thisStmt < emptyIsAGroup->size() &&
|
|
235
|
+
std::holds_alternative<bool>((*emptyIsAGroup)[thisStmt]) &&
|
|
236
|
+
std::get<bool>((*emptyIsAGroup)[thisStmt]);
|
|
237
|
+
if (!isGroup) continue;
|
|
238
|
+
}
|
|
239
|
+
|
|
193
240
|
RoleSplit split = splitByRole(stmtBodies);
|
|
194
241
|
allBg.insert(allBg.end(), split.background.begin(), split.background.end());
|
|
195
242
|
allHi.insert(allHi.end(), split.highlight.begin(), split.highlight.end());
|
|
@@ -83,6 +83,15 @@ manifold::Manifold applyRotate(manifold::Manifold body, const Value& aArg, const
|
|
|
83
83
|
return body.Transform(axisAngleMatrix(axis, angle * std::numbers::pi / 180.0));
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
+
// `a` applied after `b`, both as Manifold's column-major 3x4 affines.
|
|
87
|
+
manifold::mat3x4 compose3x4(const manifold::mat3x4& a, const manifold::mat3x4& b) {
|
|
88
|
+
manifold::mat3x4 out;
|
|
89
|
+
for (int c = 0; c < 3; ++c)
|
|
90
|
+
out[c] = a[0] * b[c].x + a[1] * b[c].y + a[2] * b[c].z;
|
|
91
|
+
out[3] = a[0] * b[3].x + a[1] * b[3].y + a[2] * b[3].z + a[3];
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
|
|
86
95
|
// Converts a user-supplied 4x4/4x3 nested-list matrix (row-major, like
|
|
87
96
|
// every OpenSCAD-facing representation) to Manifold's column-major 3x4
|
|
88
97
|
// transform. Mirrors _to_matrix4x3.
|
|
@@ -117,6 +126,121 @@ manifold::mat2x3 toMat2x3(const Value& m) {
|
|
|
117
126
|
return manifold::mat2x3(col0, col1, col2);
|
|
118
127
|
}
|
|
119
128
|
|
|
129
|
+
// The affine matrix a transform applies, for geometry Manifold cannot hold.
|
|
130
|
+
//
|
|
131
|
+
// A mesh Manifold rejected (an open surface -- a height field, a partial
|
|
132
|
+
// `vnf_vertex_array`) survives only as ColoredBody::rawMesh, raw triangles
|
|
133
|
+
// with no Manifold to transform. Those triangles were left where they were
|
|
134
|
+
// built, so `grid_copies(...) vnf_polyhedron(<open surface>)` stacked every
|
|
135
|
+
// copy at the origin and BOSL2's skin() style figure showed one shape where
|
|
136
|
+
// the reference shows seven.
|
|
137
|
+
//
|
|
138
|
+
// nullopt for `resize`, which is not a fixed map at all: its scale comes
|
|
139
|
+
// from the body's own bounding box, and a display-only body has no Manifold
|
|
140
|
+
// to measure. Verified against Manifold's own operators by
|
|
141
|
+
// TransformMatrix3d tests rather than assumed -- the Euler order especially.
|
|
142
|
+
// True if `m` is a pure translation: nothing has rotated, scaled or
|
|
143
|
+
// mirrored the section, so a further translation commutes with it.
|
|
144
|
+
bool hasIdentityLinearPart(const manifold::mat3x4& m) {
|
|
145
|
+
for (int c = 0; c < 3; ++c) {
|
|
146
|
+
const manifold::vec3 want(c == 0 ? 1.0 : 0.0, c == 1 ? 1.0 : 0.0, c == 2 ? 1.0 : 0.0);
|
|
147
|
+
if (m[c] != want) return false;
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
bool isIdentity3x4(const manifold::mat3x4& m) {
|
|
153
|
+
for (int c = 0; c < 4; ++c) {
|
|
154
|
+
const manifold::vec3 want(c == 0 ? 1.0 : 0.0, c == 1 ? 1.0 : 0.0, c == 2 ? 1.0 : 0.0);
|
|
155
|
+
if (m[c] != want) return false;
|
|
156
|
+
}
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// True if `m` maps the XY plane onto itself, so a CrossSection can hold it:
|
|
161
|
+
// nothing leaves the plane (no Z from x or y, no Z offset) and Z maps to Z.
|
|
162
|
+
bool preservesXYPlane(const manifold::mat3x4& m) {
|
|
163
|
+
return m[0].z == 0.0 && m[1].z == 0.0 && m[3].z == 0.0 &&
|
|
164
|
+
m[2].x == 0.0 && m[2].y == 0.0;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Applies `m` to a raw mesh's vertex POSITIONS in place. Any further
|
|
168
|
+
// per-vertex properties (normals and the like) are left alone: nothing
|
|
169
|
+
// reads them off a display-only body, which is drawn from its triangles.
|
|
170
|
+
void transformMeshInPlace(manifold::MeshGL& mesh, const manifold::mat3x4& m) {
|
|
171
|
+
const uint32_t stride = mesh.numProp;
|
|
172
|
+
if (stride < 3) return;
|
|
173
|
+
for (size_t i = 0; i + 2 < mesh.vertProperties.size(); i += stride) {
|
|
174
|
+
const double x = mesh.vertProperties[i];
|
|
175
|
+
const double y = mesh.vertProperties[i + 1];
|
|
176
|
+
const double z = mesh.vertProperties[i + 2];
|
|
177
|
+
const manifold::vec3 p = m[0] * x + m[1] * y + m[2] * z + m[3];
|
|
178
|
+
mesh.vertProperties[i] = static_cast<float>(p.x);
|
|
179
|
+
mesh.vertProperties[i + 1] = static_cast<float>(p.y);
|
|
180
|
+
mesh.vertProperties[i + 2] = static_cast<float>(p.z);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
std::optional<manifold::mat3x4> transformMatrix3d(const std::string& name, const CallArgs& args) {
|
|
185
|
+
const manifold::mat3x4 ident(manifold::vec3(1, 0, 0), manifold::vec3(0, 1, 0),
|
|
186
|
+
manifold::vec3(0, 0, 1), manifold::vec3(0, 0, 0));
|
|
187
|
+
if (name == "translate") {
|
|
188
|
+
manifold::mat3x4 m = ident;
|
|
189
|
+
m[3] = toVec3(getArg(args, 0, "v", Value{}));
|
|
190
|
+
return m;
|
|
191
|
+
}
|
|
192
|
+
if (name == "rotate") {
|
|
193
|
+
const Value aArg = getArg(args, 0, "a", Value{0.0});
|
|
194
|
+
const Value vArg = getArg(args, 1, "v", Value{});
|
|
195
|
+
if (std::holds_alternative<ListPtr>(aArg)) {
|
|
196
|
+
const manifold::vec3 a = toVec3(aArg);
|
|
197
|
+
const double d2r = std::numbers::pi / 180.0;
|
|
198
|
+
// X, then Y, then Z -- the order Manifold::Rotate uses, which
|
|
199
|
+
// applyTransform3d hands the same angles to.
|
|
200
|
+
const manifold::mat3x4 rx = axisAngleMatrix(manifold::vec3(1, 0, 0), a.x * d2r);
|
|
201
|
+
const manifold::mat3x4 ry = axisAngleMatrix(manifold::vec3(0, 1, 0), a.y * d2r);
|
|
202
|
+
const manifold::mat3x4 rz = axisAngleMatrix(manifold::vec3(0, 0, 1), a.z * d2r);
|
|
203
|
+
return compose3x4(rz, compose3x4(ry, rx));
|
|
204
|
+
}
|
|
205
|
+
const double angle = toDoubleLenient(aArg);
|
|
206
|
+
const manifold::vec3 axis =
|
|
207
|
+
std::holds_alternative<std::monostate>(vArg) ? manifold::vec3(0, 0, 1) : toVec3(vArg);
|
|
208
|
+
return axisAngleMatrix(axis, angle * std::numbers::pi / 180.0);
|
|
209
|
+
}
|
|
210
|
+
if (name == "scale") {
|
|
211
|
+
Value v = getArg(args, 0, "v", Value{1.0});
|
|
212
|
+
manifold::vec3 sv = std::get_if<double>(&v)
|
|
213
|
+
? manifold::vec3(*std::get_if<double>(&v), *std::get_if<double>(&v),
|
|
214
|
+
*std::get_if<double>(&v))
|
|
215
|
+
: toVec3(v, 1.0, 1.0, 1.0);
|
|
216
|
+
manifold::mat3x4 m = ident;
|
|
217
|
+
m[0] = manifold::vec3(sv.x, 0, 0);
|
|
218
|
+
m[1] = manifold::vec3(0, sv.y, 0);
|
|
219
|
+
m[2] = manifold::vec3(0, 0, sv.z);
|
|
220
|
+
return m;
|
|
221
|
+
}
|
|
222
|
+
if (name == "mirror") {
|
|
223
|
+
manifold::vec3 n = toVec3(getArg(args, 0, "v", Value{}), 1.0, 0.0, 0.0);
|
|
224
|
+
const double len2 = n.x * n.x + n.y * n.y + n.z * n.z;
|
|
225
|
+
if (len2 <= 0.0) return ident;
|
|
226
|
+
manifold::mat3x4 m = ident;
|
|
227
|
+
// I - 2 n n^T / |n|^2, written column by column.
|
|
228
|
+
for (int c = 0; c < 3; ++c) {
|
|
229
|
+
const double nc = c == 0 ? n.x : (c == 1 ? n.y : n.z);
|
|
230
|
+
m[c] = manifold::vec3((c == 0 ? 1.0 : 0.0) - 2.0 * n.x * nc / len2,
|
|
231
|
+
(c == 1 ? 1.0 : 0.0) - 2.0 * n.y * nc / len2,
|
|
232
|
+
(c == 2 ? 1.0 : 0.0) - 2.0 * n.z * nc / len2);
|
|
233
|
+
}
|
|
234
|
+
return m;
|
|
235
|
+
}
|
|
236
|
+
if (name == "multmatrix") {
|
|
237
|
+
Value m = getArg(args, 0, "m", Value{});
|
|
238
|
+
if (std::holds_alternative<std::monostate>(m)) return ident;
|
|
239
|
+
return toMat3x4(m);
|
|
240
|
+
}
|
|
241
|
+
return std::nullopt;
|
|
242
|
+
}
|
|
243
|
+
|
|
120
244
|
manifold::Manifold applyTransform3d(const std::string& name, const CallArgs& args, manifold::Manifold body) {
|
|
121
245
|
if (name == "translate") {
|
|
122
246
|
return body.Translate(toVec3(getArg(args, 0, "v", Value{})));
|
|
@@ -233,13 +357,40 @@ std::vector<ColoredBody> generateTransform(Evaluator&, const CSGParams& params,
|
|
|
233
357
|
std::vector<ColoredBody> result;
|
|
234
358
|
for (ColoredBody b : flattenCsgTree(children)) {
|
|
235
359
|
if (b.section) {
|
|
236
|
-
//
|
|
237
|
-
//
|
|
238
|
-
//
|
|
239
|
-
|
|
240
|
-
|
|
360
|
+
// A 2D-representable transform goes into the CrossSection, so
|
|
361
|
+
// 2D booleans and offset() keep operating on real 2D geometry.
|
|
362
|
+
// Anything else -- a Z translation, a rotation out of the XY
|
|
363
|
+
// plane -- has nowhere to go there and rides along on the body
|
|
364
|
+
// until the section is extruded. Once one of those has been
|
|
365
|
+
// seen, every LATER (outer) transform must ride along too, or
|
|
366
|
+
// it would be applied in the wrong order. See
|
|
367
|
+
// ColoredBody::sectionXform.
|
|
368
|
+
const std::optional<manifold::mat3x4> m = transformMatrix3d(name, args);
|
|
369
|
+
if (isIdentity3x4(b.sectionXform) && (!m || preservesXYPlane(*m))) {
|
|
370
|
+
b.section = applyTransform2d(name, args, std::move(*b.section));
|
|
371
|
+
} else if (name == "translate" && hasIdentityLinearPart(b.sectionXform)) {
|
|
372
|
+
// A translate SPLITS while nothing has rotated or scaled the
|
|
373
|
+
// section yet: x/y into the CrossSection, z into the carried
|
|
374
|
+
// transform. Translations commute, so the order is safe --
|
|
375
|
+
// and keeping x/y in the section is what lets a later 2D
|
|
376
|
+
// boolean or offset() still see real 2D geometry after a
|
|
377
|
+
// `down(1) square(10)`.
|
|
378
|
+
b.section = applyTransform2d(name, args, std::move(*b.section));
|
|
379
|
+
b.sectionXform[3].z += toVec3(getArg(args, 0, "v", Value{})).z;
|
|
380
|
+
} else if (m) {
|
|
381
|
+
b.sectionXform = compose3x4(*m, b.sectionXform);
|
|
382
|
+
}
|
|
383
|
+
// No `m` and already carrying a transform: only resize(), which
|
|
384
|
+
// the reference passes 2D children through unchanged anyway.
|
|
241
385
|
} else if (b.body) {
|
|
242
386
|
b.body = applyTransform3d(name, args, std::move(*b.body));
|
|
387
|
+
// A display-only body's real geometry is its raw triangles --
|
|
388
|
+
// the Manifold above is empty and moving it moves nothing. See
|
|
389
|
+
// transformMatrix3d.
|
|
390
|
+
if (b.rawMesh) {
|
|
391
|
+
if (std::optional<manifold::mat3x4> m = transformMatrix3d(name, args))
|
|
392
|
+
transformMeshInPlace(*b.rawMesh, *m);
|
|
393
|
+
}
|
|
243
394
|
}
|
|
244
395
|
result.push_back(std::move(b));
|
|
245
396
|
}
|
|
@@ -1348,7 +1348,21 @@ public:
|
|
|
1348
1348
|
}
|
|
1349
1349
|
out.push_back({Op::CsgGroupStart, 0, 0, nullptr});
|
|
1350
1350
|
compileStatementList(std::vector<const oscad::ASTNode*>{geoNode}, out);
|
|
1351
|
-
out
|
|
1351
|
+
// `a` = whether a group that turns out EMPTY is still an
|
|
1352
|
+
// operand: a module instantiation or a loop builds a node
|
|
1353
|
+
// whatever it contains, an `if`/block/`*` does not. Mirrors
|
|
1354
|
+
// resolveCsg's own "empty_is_a_group" (booleans.cpp), where the
|
|
1355
|
+
// full reasoning and the OpenSCAD checks live.
|
|
1356
|
+
const oscad::NodeKind k = geoNode->kind();
|
|
1357
|
+
const int emptyIsAGroup = (
|
|
1358
|
+
k == oscad::NodeKind::ModularCall ||
|
|
1359
|
+
k == oscad::NodeKind::ModularFor ||
|
|
1360
|
+
k == oscad::NodeKind::ModularIntersectionFor ||
|
|
1361
|
+
k == oscad::NodeKind::ModularLet ||
|
|
1362
|
+
k == oscad::NodeKind::ModularModifierShowOnly ||
|
|
1363
|
+
k == oscad::NodeKind::ModularModifierHighlight ||
|
|
1364
|
+
k == oscad::NodeKind::ModularModifierBackground) ? 1 : 0;
|
|
1365
|
+
out.push_back({Op::CsgGroupEnd, emptyIsAGroup, 0, nullptr});
|
|
1352
1366
|
}
|
|
1353
1367
|
out.push_back({Op::CloseExprScope, 0, 0, nullptr});
|
|
1354
1368
|
out.push_back({Op::PopCsgWrap, idx, 0, &call.position()});
|
|
@@ -1487,15 +1501,17 @@ public:
|
|
|
1487
1501
|
// form's own compile case (AssertOp's sibling, above in
|
|
1488
1502
|
// compileExpr) -- already statement-shaped (no value
|
|
1489
1503
|
// pushed, straight fall-through), so nothing new is needed
|
|
1490
|
-
// there. `.children`
|
|
1491
|
-
//
|
|
1492
|
-
//
|
|
1493
|
-
//
|
|
1494
|
-
//
|
|
1495
|
-
//
|
|
1504
|
+
// there. `.children` IS read: `echo("x") cube();` renders the
|
|
1505
|
+
// cube in the reference, and the grammar does produce those
|
|
1506
|
+
// children. They used to be dropped on the assumption that it
|
|
1507
|
+
// never did, which silently lost the geometry -- BOSL2's
|
|
1508
|
+
// debug_region() draws its whole region through
|
|
1509
|
+
// `for(...) echo(...) linear_extrude(...) region(...)` and came
|
|
1510
|
+
// out as labels with nothing under them.
|
|
1496
1511
|
auto& n = static_cast<const oscad::ModularEcho&>(stmt);
|
|
1497
1512
|
out.push_back({Op::CheckDebugStatement, internNativeStatement(&stmt), 0, nullptr});
|
|
1498
1513
|
CompiledChunk::EchoSite site;
|
|
1514
|
+
site.node = &n; // statement form: it can have children
|
|
1499
1515
|
CompileScope exprScope;
|
|
1500
1516
|
for (const auto& argPtr : n.arguments) {
|
|
1501
1517
|
if (argPtr->kind() == NodeKind::NamedArgument) {
|
|
@@ -981,6 +981,12 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
981
981
|
f.stack.pop_back();
|
|
982
982
|
}
|
|
983
983
|
ev.emitEcho(pairs);
|
|
984
|
+
// The STATEMENT form can carry children and the
|
|
985
|
+
// reference renders them; same tail as
|
|
986
|
+
// Op::AssertStatement below. Null node = the expression
|
|
987
|
+
// form (`echo(...) 1+1`), which has none.
|
|
988
|
+
if (site.node && !site.node->children.empty())
|
|
989
|
+
ev.evalChildren(site.node->children, ctx);
|
|
984
990
|
++f.pc;
|
|
985
991
|
break;
|
|
986
992
|
}
|
|
@@ -1311,7 +1317,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1311
1317
|
// ITERATION child ctxs are pushed separately, by the
|
|
1312
1318
|
// compiled loop's own Op::ForIterNext.
|
|
1313
1319
|
ev.treeStack_.emplace_back();
|
|
1314
|
-
f.csgWrapStack.push_back({site.op, randsBefore, ins.a, {}, 0});
|
|
1320
|
+
f.csgWrapStack.push_back({site.op, randsBefore, ins.a, {}, {}, 0});
|
|
1315
1321
|
++f.pc;
|
|
1316
1322
|
break;
|
|
1317
1323
|
}
|
|
@@ -1336,6 +1342,8 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1336
1342
|
ev.evalChildren(std::vector<const oscad::ASTNode*>{stmt}, ctx);
|
|
1337
1343
|
pending.groupSizes.push_back(
|
|
1338
1344
|
Value{static_cast<double>(ev.treeStack_.back().size() - before)});
|
|
1345
|
+
// A spliced child is a plain statement, never a loop.
|
|
1346
|
+
pending.emptyIsAGroup.push_back(Value{false});
|
|
1339
1347
|
}
|
|
1340
1348
|
++f.pc;
|
|
1341
1349
|
break;
|
|
@@ -1344,6 +1352,7 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1344
1352
|
PendingCsgWrap& pending = f.csgWrapStack.back();
|
|
1345
1353
|
const size_t after = ev.treeStack_.back().size();
|
|
1346
1354
|
pending.groupSizes.push_back(Value{static_cast<double>(after - pending.groupStartSize)});
|
|
1355
|
+
pending.emptyIsAGroup.push_back(Value{ins.a != 0});
|
|
1347
1356
|
++f.pc;
|
|
1348
1357
|
break;
|
|
1349
1358
|
}
|
|
@@ -1367,6 +1376,8 @@ Value driveVm(Evaluator& ev, size_t floor) {
|
|
|
1367
1376
|
if (site.includeOpParam) params["op"] = Value{pending.op};
|
|
1368
1377
|
params["group_sizes"] =
|
|
1369
1378
|
Value{std::make_shared<const ValueList>(ValueList{std::move(pending.groupSizes)})};
|
|
1379
|
+
params["empty_is_a_group"] = Value{std::make_shared<const ValueList>(
|
|
1380
|
+
ValueList{std::move(pending.emptyIsAGroup)})};
|
|
1370
1381
|
// Mirrors Evaluator::buildTreeNode's own post-
|
|
1371
1382
|
// resolveBody() half exactly (csg_resolve.cpp).
|
|
1372
1383
|
const bool uncacheable =
|
|
@@ -37,10 +37,10 @@ std::vector<ColoredBody> toRenderableBodies(const std::vector<ColoredBody>& bodi
|
|
|
37
37
|
if (!cb.body && cb.section) {
|
|
38
38
|
ColoredBody flat;
|
|
39
39
|
flat.body = manifold::Manifold::Extrude(cb.section->ToPolygons(), kTopLevel2dHeight);
|
|
40
|
-
// Put it back where
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
40
|
+
// Put it back where the transforms a CrossSection could not
|
|
41
|
+
// hold would have placed it -- a Z offset, a rotation out of
|
|
42
|
+
// the plane. See ColoredBody::sectionXform.
|
|
43
|
+
flat.body = flat.body->Transform(cb.sectionXform);
|
|
44
44
|
flat.color = cb.color;
|
|
45
45
|
flat.flatPreview = true;
|
|
46
46
|
flat.role = cb.role;
|
|
@@ -241,9 +241,17 @@ void Evaluator::evalStatement(const oscad::ASTNode& node, EvalContext& ctx) {
|
|
|
241
241
|
case oscad::NodeKind::ModularLet:
|
|
242
242
|
evalLetBlock(static_cast<const oscad::ModularLet&>(node), ctx);
|
|
243
243
|
return;
|
|
244
|
-
case oscad::NodeKind::ModularEcho:
|
|
245
|
-
|
|
244
|
+
case oscad::NodeKind::ModularEcho: {
|
|
245
|
+
// `echo("x") cube();` echoes AND renders the cube, the way the
|
|
246
|
+
// reference does and the way ModularAssert already did here.
|
|
247
|
+
// Dropping the children silently lost geometry: BOSL2's
|
|
248
|
+
// debug_region() draws its whole region through
|
|
249
|
+
// `for(...) echo(...) linear_extrude(...) region(...)`.
|
|
250
|
+
const auto& e = static_cast<const oscad::ModularEcho&>(node);
|
|
251
|
+
doEcho(e.arguments, ctx);
|
|
252
|
+
if (!e.children.empty()) evalChildren(e.children, ctx);
|
|
246
253
|
return;
|
|
254
|
+
}
|
|
247
255
|
case oscad::NodeKind::ModularAssert:
|
|
248
256
|
evalAssertStatement(static_cast<const oscad::ModularAssert&>(node), ctx);
|
|
249
257
|
return;
|