openscad-cpp-evaluator 1.14.0__tar.gz → 1.15.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.14.0 → openscad_cpp_evaluator-1.15.0}/CLAUDE.md +16 -1
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/bindings/module.cpp +9 -2
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/export.hpp +8 -1
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/python/openscad_cpp_evaluator/__init__.py +8 -1
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/text.cpp +12 -1
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/export.cpp +16 -4
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_export.cpp +60 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_python_bindings.py +21 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_text.cpp +27 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/README.md +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/uv.lock +0 -0
|
@@ -298,6 +298,13 @@ variable real OpenSCAD reads). Family match is case-insensitive and required; st
|
|
|
298
298
|
dropping to Regular beats falling through to an unrelated family, which is what fontconfig does
|
|
299
299
|
too.
|
|
300
300
|
|
|
301
|
+
**`text()` takes `font` positionally too — and NOTHING after it.** `text(text, size, font)` is the
|
|
302
|
+
positional set; `halign`/`valign`/`spacing`/`direction`/`language`/`script` are name-only, because
|
|
303
|
+
that is what the 2026.02.01 binary does: `text("Hi", 10, "F", "center")` is not centred there while
|
|
304
|
+
`halign="center"` is, measured by bounding box. So **`text()` and `textmetrics()` genuinely differ**
|
|
305
|
+
— the latter takes all nine positionally — and neither can be assumed from the other. `font` being
|
|
306
|
+
name-only made `text("Hi", 10, "Liberation Sans:style=Bold")` silently draw the default face.
|
|
307
|
+
|
|
301
308
|
**`font` is a POSITIONAL argument in both metrics functions**, and so is everything after it:
|
|
302
309
|
`fontmetrics(size, font)` and `textmetrics(text, size, font, direction, language, script, halign,
|
|
303
310
|
valign, spacing)`. Verified against the 2026.02.01 binary rather than read off a doc page. Having
|
|
@@ -970,7 +977,15 @@ grep for `ponytail:`.
|
|
|
970
977
|
restating the list, because three hand-written copies had already drifted far enough that `.off`
|
|
971
978
|
could be written by neither the GUI nor the CLI while every test passed.
|
|
972
979
|
Colour is carried by 3MF, AMF, OBJ (companion `.mtl`), PLY, VRML and X3D; STL and OFF compose
|
|
973
|
-
every body into one solid and store geometry only.
|
|
980
|
+
every body into one solid and store geometry only.
|
|
981
|
+
**`ExportOptions::splitColors` picks what the file is FOR**, and is the axis worth asking a user
|
|
982
|
+
about rather than "should parts be separate": on (the default) writes one object per colour, which
|
|
983
|
+
is what a **multi-material** print wants — each colour is something the slicer assigns to a
|
|
984
|
+
filament. Off is a **single-material** print: everything unions into one welded solid, so touching
|
|
985
|
+
colour regions lose the coincident faces that stacking per-colour objects would leave, and the
|
|
986
|
+
per-triangle colour is dropped because such a print has no use for it. Implemented by forcing
|
|
987
|
+
`splitBodiesForExport`'s `allSame` branch, which already unions rather than concatenates —
|
|
988
|
+
concatenating the per-colour objects instead would have left the seam. **AMF** puts colour on the `<volume>` rather
|
|
974
989
|
than the face, so an object whose triangles are not all one colour is written as one volume per
|
|
975
990
|
colour — per-triangle `<color>` is legal in the spec but poorly supported by the slicers that are
|
|
976
991
|
the audience for it.
|
|
@@ -404,7 +404,8 @@ void applyPdfOptions(const nb::dict& d, oscadeval::ExportPdfOptions& pdf) {
|
|
|
404
404
|
}
|
|
405
405
|
|
|
406
406
|
nb::list exportModelPy(const std::string& path, const Geometry& geom, const std::string& format, bool asciiStl,
|
|
407
|
-
bool stripSlivers, bool splitComponents, bool
|
|
407
|
+
bool stripSlivers, bool splitComponents, bool splitColors, bool svgFill,
|
|
408
|
+
const std::string& svgFillColor,
|
|
408
409
|
bool svgStroke, const std::string& svgStrokeColor, double svgStrokeWidth,
|
|
409
410
|
nb::object pdfOptions) {
|
|
410
411
|
oscadeval::ExportPdfOptions pdf;
|
|
@@ -418,6 +419,7 @@ nb::list exportModelPy(const std::string& path, const Geometry& geom, const std:
|
|
|
418
419
|
opts.asciiStl = asciiStl;
|
|
419
420
|
opts.stripSlivers = stripSlivers;
|
|
420
421
|
opts.splitComponents = splitComponents;
|
|
422
|
+
opts.splitColors = splitColors;
|
|
421
423
|
opts.svg.fill = svgFill;
|
|
422
424
|
opts.svg.fillColor = svgFillColor;
|
|
423
425
|
opts.svg.stroke = svgStroke;
|
|
@@ -850,7 +852,8 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
850
852
|
|
|
851
853
|
m.def("export_model", &exportModelPy, nb::arg("path"), nb::arg("geometry"), nb::arg("format") = std::string(),
|
|
852
854
|
nb::arg("ascii_stl") = false, nb::arg("strip_slivers") = true,
|
|
853
|
-
nb::arg("split_components") = false, nb::arg("
|
|
855
|
+
nb::arg("split_components") = false, nb::arg("split_colors") = true,
|
|
856
|
+
nb::arg("svg_fill") = false,
|
|
854
857
|
nb::arg("svg_fill_color") = std::string("white"), nb::arg("svg_stroke") = true,
|
|
855
858
|
nb::arg("svg_stroke_color") = std::string("black"), nb::arg("svg_stroke_width") = 0.35,
|
|
856
859
|
nb::arg("pdf_options") = nb::none(),
|
|
@@ -861,6 +864,10 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
861
864
|
"`split_components` gives every disconnected piece its own object in the multi-object formats "
|
|
862
865
|
"(3MF, AMF, OBJ, PLY, VRML, X3D). Off by default, matching OpenSCAD, which writes one object "
|
|
863
866
|
"per colour however many pieces it is in.\n\n"
|
|
867
|
+
"`split_colors` (on by default) writes one object per colour -- what a MULTI-MATERIAL print "
|
|
868
|
+
"wants, each colour being something the slicer assigns to a filament. Turn it off for a "
|
|
869
|
+
"single-material print: everything welds into one solid, with no seams between colour "
|
|
870
|
+
"regions and no per-triangle colour it has no use for.\n\n"
|
|
864
871
|
"The svg_* arguments are OpenSCAD's -O export-svg/... set and apply to .svg only. "
|
|
865
872
|
"svg_stroke/svg_stroke_width also pad the page, so they are not purely cosmetic. An .svg "
|
|
866
873
|
"export needs an all-2D model and raises otherwise, as OpenSCAD does.\n\n"
|
|
@@ -53,7 +53,8 @@ struct ExportObject {
|
|
|
53
53
|
// 1-based index is appended to `openParts` for the caller to warn about.
|
|
54
54
|
std::vector<ExportObject> splitBodiesForExport(const std::vector<ColoredBody>& bodies,
|
|
55
55
|
std::vector<int>* openParts = nullptr,
|
|
56
|
-
bool splitComponents = false
|
|
56
|
+
bool splitComponents = false,
|
|
57
|
+
bool splitColors = true);
|
|
57
58
|
|
|
58
59
|
// Writes a binary STL: composes every body's mesh into one solid (bodies
|
|
59
60
|
// with no `.body` -- 2D-only sections -- or an empty Manifold are
|
|
@@ -236,6 +237,12 @@ struct ExportOptions {
|
|
|
236
237
|
// pieces it is in; see that function's own comment for why the default
|
|
237
238
|
// moved here.
|
|
238
239
|
bool splitComponents = false;
|
|
240
|
+
// Rule 2 of splitBodiesForExport: one object per colour. That is what
|
|
241
|
+
// a MULTI-MATERIAL print wants -- each colour becomes something the
|
|
242
|
+
// slicer assigns to a filament. Turn it off for a single-material
|
|
243
|
+
// print, which wants one welded solid instead: no seams between
|
|
244
|
+
// colour regions, and no per-triangle colour it has no use for.
|
|
245
|
+
bool splitColors = true;
|
|
239
246
|
// .svg only.
|
|
240
247
|
ExportSvgOptions svg;
|
|
241
248
|
// .pdf only.
|
|
@@ -293,6 +293,7 @@ def strip_slivers(verts, tris):
|
|
|
293
293
|
|
|
294
294
|
def export_model(path: str, geometry, format: str = "", ascii_stl: bool = False,
|
|
295
295
|
strip_slivers: bool = True, split_components: bool = False,
|
|
296
|
+
split_colors: bool = True,
|
|
296
297
|
svg_fill: bool = False, svg_fill_color: str = "white",
|
|
297
298
|
svg_stroke: bool = True, svg_stroke_color: str = "black",
|
|
298
299
|
svg_stroke_width: float = 0.35, pdf_options: dict | None = None) -> list:
|
|
@@ -316,6 +317,12 @@ def export_model(path: str, geometry, format: str = "", ascii_stl: bool = False,
|
|
|
316
317
|
`split_components` gives every disconnected piece its own object in the
|
|
317
318
|
multi-object formats. Off by default, which is what OpenSCAD writes.
|
|
318
319
|
|
|
320
|
+
`split_colors` (on by default) writes one object per colour -- what a
|
|
321
|
+
MULTI-MATERIAL print wants, each colour being something the slicer
|
|
322
|
+
assigns to a filament. Turn it off for a single-material print:
|
|
323
|
+
everything welds into one solid, with no seams between colour regions
|
|
324
|
+
and no per-triangle colour it has no use for.
|
|
325
|
+
|
|
319
326
|
The `svg_*` arguments are OpenSCAD's `-O export-svg/...` set and apply
|
|
320
327
|
to `.svg` only, which writes a 2D model at 1:1 in millimetres.
|
|
321
328
|
`svg_stroke`/`svg_stroke_width` also pad the page, so they are not
|
|
@@ -335,7 +342,7 @@ def export_model(path: str, geometry, format: str = "", ascii_stl: bool = False,
|
|
|
335
342
|
"""
|
|
336
343
|
try:
|
|
337
344
|
return list(_ext.export_model(path, geometry, format, ascii_stl, strip_slivers,
|
|
338
|
-
split_components, svg_fill, svg_fill_color,
|
|
345
|
+
split_components, split_colors, svg_fill, svg_fill_color,
|
|
339
346
|
svg_stroke, svg_stroke_color, svg_stroke_width,
|
|
340
347
|
pdf_options))
|
|
341
348
|
except Exception as e:
|
|
@@ -34,7 +34,18 @@ CSGParams resolveText(Evaluator& ev, const oscad::ModularCall& node, EvalContext
|
|
|
34
34
|
auto [args, effCtx] = resolveCallArgs(ev, node.arguments, ctx);
|
|
35
35
|
const std::string text = asStringOr(getArg(args, 0, "text", Value{std::string("")}), "");
|
|
36
36
|
const double size = toDoubleLenient(getArg(args, 1, "size", Value{10.0}));
|
|
37
|
-
|
|
37
|
+
// font is POSITIONAL, at index 2: `text("Hi", 10, "Liberation Sans")`
|
|
38
|
+
// is how people write it and how the reference reads it -- measured
|
|
39
|
+
// against the 2026.02.01 binary, whose bounding box for the
|
|
40
|
+
// positional form matches the named one exactly.
|
|
41
|
+
//
|
|
42
|
+
// Only font. halign/valign/spacing/direction/language/script stay
|
|
43
|
+
// name-only, because the same measurement shows the reference
|
|
44
|
+
// ignoring them positionally: `text("Hi", 10, "F", "center")` is NOT
|
|
45
|
+
// centred there, while halign="center" is. text() and textmetrics()
|
|
46
|
+
// genuinely differ here -- textmetrics takes all nine positionally --
|
|
47
|
+
// so neither can be assumed from the other.
|
|
48
|
+
const std::string fontSpec = asStringOr(getArg(args, 2, "font", Value{std::string("")}), "");
|
|
38
49
|
const std::string halign = asStringOr(getArg(args, std::nullopt, "halign", Value{std::string("left")}), "left");
|
|
39
50
|
const std::string valign = asStringOr(getArg(args, std::nullopt, "valign", Value{std::string("baseline")}), "baseline");
|
|
40
51
|
const double spacing = toDoubleLenient(getArg(args, std::nullopt, "spacing", Value{1.0}));
|
|
@@ -421,7 +421,7 @@ std::vector<std::array<float, 4>> carryTriColors(const std::vector<std::array<fl
|
|
|
421
421
|
} // namespace
|
|
422
422
|
|
|
423
423
|
std::vector<ExportObject> splitBodiesForExport(const std::vector<ColoredBody>& bodies, std::vector<int>* openParts,
|
|
424
|
-
bool splitComponents) {
|
|
424
|
+
bool splitComponents, bool splitColors) {
|
|
425
425
|
struct Solid {
|
|
426
426
|
manifold::Manifold man;
|
|
427
427
|
std::optional<std::array<float, 4>> color;
|
|
@@ -484,7 +484,15 @@ std::vector<ExportObject> splitBodiesForExport(const std::vector<ColoredBody>& b
|
|
|
484
484
|
if (k.hasColor) k.color = *solids[i].color;
|
|
485
485
|
keys.push_back(k);
|
|
486
486
|
}
|
|
487
|
-
|
|
487
|
+
// Splitting by colour is for a MULTI-MATERIAL print, where each
|
|
488
|
+
// colour becomes an object the slicer assigns to a filament. A
|
|
489
|
+
// single-material print wants the opposite: one welded solid, with
|
|
490
|
+
// no seams between colour regions for the slicer to treat as
|
|
491
|
+
// separate walls. Unioning everything here (rather than
|
|
492
|
+
// concatenating the per-colour objects afterwards) is what makes
|
|
493
|
+
// touching regions weld instead of leaving coincident faces.
|
|
494
|
+
const bool allSame = !splitColors ||
|
|
495
|
+
std::all_of(keys.begin(), keys.end(), [&](const ColorKey& k) { return k == keys[0]; });
|
|
488
496
|
|
|
489
497
|
if (allSame) {
|
|
490
498
|
// The common case by far, and it needs no per-body subtraction
|
|
@@ -496,7 +504,10 @@ std::vector<ExportObject> splitBodiesForExport(const std::vector<ColoredBody>& b
|
|
|
496
504
|
Claimed c;
|
|
497
505
|
c.man = addAll(parts);
|
|
498
506
|
c.color = solids[0].color;
|
|
499
|
-
|
|
507
|
+
// Per-triangle colour cannot survive a weld across colours --
|
|
508
|
+
// the union rebuilds the surface -- and a single-material
|
|
509
|
+
// print has no use for it anyway.
|
|
510
|
+
c.triColors = splitColors ? solids[0].triColors : std::vector<std::array<float, 4>>{};
|
|
500
511
|
c.sourceTris = solids[0].tris;
|
|
501
512
|
c.key = keys[0];
|
|
502
513
|
claimedGroups.push_back(std::move(c));
|
|
@@ -1507,7 +1518,8 @@ std::vector<std::string> exportModel(const std::string& path, const std::vector<
|
|
|
1507
1518
|
// its own -- that is what the file contains.
|
|
1508
1519
|
for (std::string& w : checkExportBodies(bodies)) warnings.push_back(std::move(w));
|
|
1509
1520
|
std::vector<int> openParts;
|
|
1510
|
-
const std::vector<ExportObject> objects =
|
|
1521
|
+
const std::vector<ExportObject> objects =
|
|
1522
|
+
splitBodiesForExport(bodies, &openParts, opts.splitComponents, opts.splitColors);
|
|
1511
1523
|
reportOpen(openParts);
|
|
1512
1524
|
if (objects.empty()) throw std::runtime_error("No geometry to export");
|
|
1513
1525
|
if (ext == ".3mf") {
|
|
@@ -733,3 +733,63 @@ TEST(ExportPdf, ReachableThroughExportModelAndListedAsAnExtension) {
|
|
|
733
733
|
std::remove(path.c_str());
|
|
734
734
|
}
|
|
735
735
|
|
|
736
|
+
|
|
737
|
+
// -- single-material vs multi-material -------------------------------------
|
|
738
|
+
|
|
739
|
+
TEST(SplitColors, MultiMaterialGivesOneObjectPerColour) {
|
|
740
|
+
// The default: each colour becomes something a slicer can assign to a
|
|
741
|
+
// filament.
|
|
742
|
+
std::vector<ColoredBody> bodies =
|
|
743
|
+
evalToBodies("color(\"red\") cube(10); color(\"blue\") translate([12,0,0]) cube(10);");
|
|
744
|
+
const std::vector<ExportObject> objs = splitBodiesForExport(bodies, nullptr, false, /*splitColors=*/true);
|
|
745
|
+
EXPECT_EQ(objs.size(), 2u);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
TEST(SplitColors, SingleMaterialGivesOneObject) {
|
|
749
|
+
// A single-material print has nothing to do with the colours, and
|
|
750
|
+
// splitting on them only gives the slicer parts to list.
|
|
751
|
+
std::vector<ColoredBody> bodies =
|
|
752
|
+
evalToBodies("color(\"red\") cube(10); color(\"blue\") translate([12,0,0]) cube(10);");
|
|
753
|
+
const std::vector<ExportObject> objs = splitBodiesForExport(bodies, nullptr, false, /*splitColors=*/false);
|
|
754
|
+
ASSERT_EQ(objs.size(), 1u);
|
|
755
|
+
EXPECT_TRUE(objs[0].triColors.empty()); // no per-triangle colour to carry
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
TEST(SplitColors, SingleMaterialWeldsTouchingColourRegions) {
|
|
759
|
+
// Unioned, not concatenated: two touching cubes of different colours
|
|
760
|
+
// must come out as one solid without the coincident interior faces
|
|
761
|
+
// that stacking the per-colour objects would leave behind.
|
|
762
|
+
std::vector<ColoredBody> bodies =
|
|
763
|
+
evalToBodies("color(\"red\") cube(10); color(\"blue\") translate([10,0,0]) cube(10);");
|
|
764
|
+
const std::vector<ExportObject> single = splitBodiesForExport(bodies, nullptr, false, /*splitColors=*/false);
|
|
765
|
+
ASSERT_EQ(single.size(), 1u);
|
|
766
|
+
|
|
767
|
+
const std::vector<ExportObject> multi = splitBodiesForExport(bodies, nullptr, false, true);
|
|
768
|
+
ASSERT_EQ(multi.size(), 2u);
|
|
769
|
+
size_t multiTris = 0;
|
|
770
|
+
for (const ExportObject& o : multi) multiTris += o.tris.size() / 3;
|
|
771
|
+
|
|
772
|
+
// Fewer triangles than the two objects have between them: the pair of
|
|
773
|
+
// coincident faces along the seam is gone, which is the difference
|
|
774
|
+
// between a welded solid and two boxes stacked in one object. (Not
|
|
775
|
+
// the 12 of a plain 20x10x10 box -- Manifold keeps the seam's
|
|
776
|
+
// vertices, so the faces crossing it stay split.)
|
|
777
|
+
EXPECT_LT(single[0].tris.size() / 3, multiTris);
|
|
778
|
+
EXPECT_EQ(single[0].tris.size() / 3, 20u);
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
TEST(SplitColors, SingleMaterialKeepsTheWholeVolume) {
|
|
782
|
+
std::vector<ColoredBody> bodies =
|
|
783
|
+
evalToBodies("color(\"red\") cube(10); color(\"blue\") translate([12,0,0]) cube(10);");
|
|
784
|
+
const std::vector<ExportObject> multi = splitBodiesForExport(bodies, nullptr, false, true);
|
|
785
|
+
const std::vector<ExportObject> single = splitBodiesForExport(bodies, nullptr, false, false);
|
|
786
|
+
size_t multiTris = 0;
|
|
787
|
+
for (const ExportObject& o : multi) multiTris += o.tris.size();
|
|
788
|
+
EXPECT_EQ(single[0].tris.size(), multiTris); // same surface, one object
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
TEST(SplitColors, AnUncolouredModelIsUnaffectedEitherWay) {
|
|
792
|
+
std::vector<ColoredBody> bodies = evalToBodies("cube(10); translate([12,0,0]) cube(10);");
|
|
793
|
+
EXPECT_EQ(splitBodiesForExport(bodies, nullptr, false, true).size(), 1u);
|
|
794
|
+
EXPECT_EQ(splitBodiesForExport(bodies, nullptr, false, false).size(), 1u);
|
|
795
|
+
}
|
{openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/tests/test_python_bindings.py
RENAMED
|
@@ -776,6 +776,27 @@ def test_list_fonts_reports_specs_that_actually_resolve(tmp_path):
|
|
|
776
776
|
assert echoes == ['ECHO: "Regular"', 'ECHO: "Bold"', 'ECHO: "Italic"', 'ECHO: "Bold Italic"']
|
|
777
777
|
|
|
778
778
|
|
|
779
|
+
def test_split_colors_chooses_single_or_multi_material(tmp_path):
|
|
780
|
+
"""Same two-hand-written-parameter-lists trap as split_components."""
|
|
781
|
+
from openscad_cpp_evaluator import Evaluator, export_model
|
|
782
|
+
|
|
783
|
+
src = tmp_path / "two.scad"
|
|
784
|
+
src.write_text('color("red") cube(10); color("blue") translate([12,0,0]) cube(10);')
|
|
785
|
+
ev = Evaluator()
|
|
786
|
+
ev.evaluate(str(src), {})
|
|
787
|
+
|
|
788
|
+
def objects_in(path, **kwargs):
|
|
789
|
+
import zipfile
|
|
790
|
+
export_model(str(path), ev.geometry, **kwargs)
|
|
791
|
+
with zipfile.ZipFile(path) as z:
|
|
792
|
+
return z.read("3D/3dmodel.model").decode().count("<object ")
|
|
793
|
+
|
|
794
|
+
# Multi-material (the default): one object per colour for the slicer.
|
|
795
|
+
assert objects_in(tmp_path / "multi.3mf") == 2
|
|
796
|
+
# Single-material: one solid, colours irrelevant.
|
|
797
|
+
assert objects_in(tmp_path / "single.3mf", split_colors=False) == 1
|
|
798
|
+
|
|
799
|
+
|
|
779
800
|
def test_strict_commas_reaches_the_parser(tmp_path):
|
|
780
801
|
"""Evaluator.evaluate(strict_commas=True) must survive both hand-written
|
|
781
802
|
parameter lists -- the facade's and the nanobind binding's. The last
|
|
@@ -379,3 +379,30 @@ TEST(FontArgs, TheLaterPositionalsLineUpToo) {
|
|
|
379
379
|
ASSERT_EQ(echoes.size(), 1u);
|
|
380
380
|
EXPECT_EQ(echoes[0], "ECHO: true, true");
|
|
381
381
|
}
|
|
382
|
+
|
|
383
|
+
TEST(TextArgs, FontIsPositionalButTheRestAreNot) {
|
|
384
|
+
// text("Hi", 10, "Liberation Sans:style=Bold") silently drew the
|
|
385
|
+
// DEFAULT face: `font` was name-only, so the third argument went
|
|
386
|
+
// nowhere. Same defect as BelfrySCAD #381's, in the module people
|
|
387
|
+
// actually use.
|
|
388
|
+
//
|
|
389
|
+
// And only `font`: the reference accepts nothing after it
|
|
390
|
+
// positionally, which was measured rather than assumed --
|
|
391
|
+
// `text("Hi", 10, "F", "center")` is not centred in OpenSCAD
|
|
392
|
+
// 2026.02.01, while halign="center" is. textmetrics() differs from
|
|
393
|
+
// text() here, taking all nine positionally.
|
|
394
|
+
std::vector<std::string> echoes;
|
|
395
|
+
Evaluated e = evalSrc(
|
|
396
|
+
"p = render() { linear_extrude(1) text(\"Hi\", 10, \"Liberation Sans:style=Bold\"); };\n"
|
|
397
|
+
"n = render() { linear_extrude(1) text(\"Hi\", 10, font=\"Liberation Sans:style=Bold\"); };\n"
|
|
398
|
+
"d = render() { linear_extrude(1) text(\"Hi\", 10); };\n"
|
|
399
|
+
"h = render() { linear_extrude(1) text(\"Hi\", 10, \"Liberation Sans\", \"center\"); };\n"
|
|
400
|
+
"hn = render() { linear_extrude(1) text(\"Hi\", 10, \"Liberation Sans\", halign=\"center\"); };\n"
|
|
401
|
+
"echo(p.volume == n.volume, p.volume == d.volume, h.boundingbox == d.boundingbox,"
|
|
402
|
+
" hn.boundingbox == d.boundingbox);\n",
|
|
403
|
+
[&](const std::string& m) { echoes.push_back(m); });
|
|
404
|
+
ASSERT_EQ(echoes.size(), 1u);
|
|
405
|
+
// positional == named, positional != default, a 4th positional does
|
|
406
|
+
// NOTHING, and halign by name does move it.
|
|
407
|
+
EXPECT_EQ(echoes[0], "ECHO: true, false, true, false");
|
|
408
|
+
}
|
|
File without changes
|
{openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.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.14.0 → openscad_cpp_evaluator-1.15.0}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.0}/examples/manifold_cache_reuse.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-1.14.0 → openscad_cpp_evaluator-1.15.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
|
|
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
|
|
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
|