openscad-cpp-evaluator 0.14.0__tar.gz → 0.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-0.14.0 → openscad_cpp_evaluator-0.15.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/bindings/module.cpp +9 -3
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/colored_body.hpp +21 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/evaluator.hpp +12 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/booleans.cpp +15 -2
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/builtins.hpp +13 -1
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/import.cpp +33 -24
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/primitives_3d.cpp +64 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/topology.cpp +2 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/csg_generate.cpp +23 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_import_export.cpp +8 -1
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_primitives.cpp +92 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/README.md +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/text/stb_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/uv.lock +0 -0
|
@@ -129,7 +129,11 @@ const char* roleToString(oscadeval::BodyRole role) {
|
|
|
129
129
|
// tri_verts (nTri, 3), run_original_id (nRun,), run_index (nRun+1,) -- the
|
|
130
130
|
// same flat 3*triangle units manifold3d's own run_index uses).
|
|
131
131
|
nb::dict bodyToDict(oscadeval::ColoredBody& cb) {
|
|
132
|
-
|
|
132
|
+
// A display-only body's Manifold is empty by construction, so its
|
|
133
|
+
// GetMeshGL() would hand back nothing -- take the raw triangle soup
|
|
134
|
+
// that failed to build instead. Everything downstream reads plain
|
|
135
|
+
// arrays, so the two cases are indistinguishable from here on.
|
|
136
|
+
manifold::MeshGL mesh = cb.isDisplayOnly() ? *cb.rawMesh : cb.body->GetMeshGL();
|
|
133
137
|
const size_t numProp = mesh.numProp;
|
|
134
138
|
const size_t numVert = numProp ? mesh.vertProperties.size() / numProp : 0;
|
|
135
139
|
const size_t numTri = mesh.triVerts.size() / 3;
|
|
@@ -184,7 +188,9 @@ void collectIdSpans(const oscadeval::Evaluator& ev, std::vector<IdSpan>& out) {
|
|
|
184
188
|
nb::list bodiesToList(std::vector<oscadeval::ColoredBody>& bodies) {
|
|
185
189
|
nb::list out;
|
|
186
190
|
for (oscadeval::ColoredBody& cb : bodies) {
|
|
187
|
-
|
|
191
|
+
// isDisplayOnly() bodies are ALWAYS IsEmpty() -- that's what made
|
|
192
|
+
// an open polyhedron() silently vanish here rather than render.
|
|
193
|
+
if (!cb.isDisplayOnly() && (!cb.body || cb.body->IsEmpty())) continue;
|
|
188
194
|
out.append(bodyToDict(cb));
|
|
189
195
|
}
|
|
190
196
|
return out;
|
|
@@ -210,7 +216,7 @@ nb::object csgNodeToPy(const oscadeval::CSGNode& node) {
|
|
|
210
216
|
for (const auto& [k, v] : node.params) params[nb::str(k.c_str())] = valueToPy(v);
|
|
211
217
|
nb::list bodies;
|
|
212
218
|
for (const oscadeval::ColoredBody& cb : node.bodies) {
|
|
213
|
-
if (!cb.body || cb.body->IsEmpty()) continue;
|
|
219
|
+
if (!cb.isDisplayOnly() && (!cb.body || cb.body->IsEmpty())) continue;
|
|
214
220
|
// ColoredBody here is const in this walk (tree ownership stays with
|
|
215
221
|
// the caller) -- GetMeshGL() itself is logically read-only, so a
|
|
216
222
|
// const_cast here is safe/local, mirroring bodyToDict's mutating
|
|
@@ -26,6 +26,27 @@ struct ColoredBody {
|
|
|
26
26
|
bool flatPreview = false;
|
|
27
27
|
BodyRole role = BodyRole::Normal;
|
|
28
28
|
std::optional<std::vector<std::array<float, 4>>> triColors; // per-triangle RGBA, multi-color CSG merges only
|
|
29
|
+
|
|
30
|
+
// Set ONLY when a mesh could not be built into a valid Manifold -- in
|
|
31
|
+
// practice a polyhedron() whose faces don't close the surface (it has
|
|
32
|
+
// boundary edges), which Manifold reports by returning an *empty* body
|
|
33
|
+
// with Status() == NotManifold rather than by failing. Note the status
|
|
34
|
+
// name is misleading: a closed mesh with reversed winding, non-manifold
|
|
35
|
+
// vertices or self-intersections builds fine; only an OPEN one lands
|
|
36
|
+
// here.
|
|
37
|
+
//
|
|
38
|
+
// Carrying the raw triangle soup alongside lets the renderer still draw
|
|
39
|
+
// what the script described, which is far more use for spotting the
|
|
40
|
+
// missing face than an empty viewport. `body` is deliberately left set
|
|
41
|
+
// (and empty), so every existing `cb.body->...` path keeps working.
|
|
42
|
+
//
|
|
43
|
+
// Such a body is display-only: it can never take part in a CSG
|
|
44
|
+
// operation, since there is no Manifold for Manifold to operate on.
|
|
45
|
+
// splitByRole() pulls it aside much as it does a `%` background body,
|
|
46
|
+
// and the CSG/hull/minkowski generators re-join it unchanged.
|
|
47
|
+
std::optional<manifold::MeshGL> rawMesh;
|
|
48
|
+
|
|
49
|
+
bool isDisplayOnly() const { return rawMesh.has_value(); }
|
|
29
50
|
};
|
|
30
51
|
|
|
31
52
|
// `EvalContext::color`/CSGParams round-trip: a resolve function reads
|
|
@@ -236,6 +236,18 @@ public:
|
|
|
236
236
|
// comment for why that reference exists at all).
|
|
237
237
|
ColoredBody tagGenerated(manifold::Manifold body, const oscad::ASTNode& node, const Value& colorValue);
|
|
238
238
|
|
|
239
|
+
// tagGenerated()'s counterpart for a mesh Manifold refused to build --
|
|
240
|
+
// an open polyhedron(). Returns a display-only ColoredBody (see
|
|
241
|
+
// ColoredBody::rawMesh) carrying the triangle soup as-is, so it can
|
|
242
|
+
// still be drawn even though no CSG operation can ever touch it.
|
|
243
|
+
//
|
|
244
|
+
// A failed Manifold has no run IDs of its own, so one is reserved here
|
|
245
|
+
// and written onto the raw mesh -- otherwise the body would be
|
|
246
|
+
// invisible to selection and to the originalID -> AST node mapping
|
|
247
|
+
// that drives click-to-source, which is exactly when a user most wants
|
|
248
|
+
// to click the broken thing and be shown the line that made it.
|
|
249
|
+
ColoredBody tagDisplayOnly(manifold::MeshGL mesh, const oscad::ASTNode& node, const Value& colorValue);
|
|
250
|
+
|
|
239
251
|
// Raises an OpenSCAD-level runtime error: throws EvalError with the
|
|
240
252
|
// formatted "ERROR: {msg}{TRACE lines}" message (see eval_error.hpp),
|
|
241
253
|
// walking the real user function/module call stack for the TRACE lines
|
|
@@ -27,8 +27,19 @@ RoleSplit splitByRole(const std::vector<ColoredBody>& bodies) {
|
|
|
27
27
|
for (const ColoredBody& c : bodies) {
|
|
28
28
|
if (c.role == BodyRole::Background) r.background.push_back(c);
|
|
29
29
|
}
|
|
30
|
+
// Checked before the foreground sweep below and excluded from it: a
|
|
31
|
+
// display-only body has an empty Manifold, so letting it reach a
|
|
32
|
+
// boolean would silently zero the whole operation (the same failure
|
|
33
|
+
// mode invalid operands caused before they were filtered out).
|
|
30
34
|
for (const ColoredBody& c : bodies) {
|
|
31
|
-
if (c.role != BodyRole::Background && c.role != BodyRole::ShowOnly)
|
|
35
|
+
if (c.isDisplayOnly() && c.role != BodyRole::Background && c.role != BodyRole::ShowOnly) {
|
|
36
|
+
r.displayOnly.push_back(c);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
for (const ColoredBody& c : bodies) {
|
|
40
|
+
if (c.role != BodyRole::Background && c.role != BodyRole::ShowOnly && !c.isDisplayOnly()) {
|
|
41
|
+
r.foreground.push_back(c);
|
|
42
|
+
}
|
|
32
43
|
}
|
|
33
44
|
for (const ColoredBody& c : r.foreground) {
|
|
34
45
|
if (c.role == BodyRole::Highlight) r.highlight.push_back(c);
|
|
@@ -160,7 +171,7 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
160
171
|
const std::string& op = std::get<std::string>(params.at("op"));
|
|
161
172
|
const auto& groupSizes = std::get<ListPtr>(params.at("group_sizes"))->items;
|
|
162
173
|
|
|
163
|
-
std::vector<ColoredBody> allBg, allHi, allSo;
|
|
174
|
+
std::vector<ColoredBody> allBg, allHi, allSo, allDo;
|
|
164
175
|
std::optional<ColoredBody> csgResult;
|
|
165
176
|
size_t idx = 0;
|
|
166
177
|
|
|
@@ -173,6 +184,7 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
173
184
|
allBg.insert(allBg.end(), split.background.begin(), split.background.end());
|
|
174
185
|
allHi.insert(allHi.end(), split.highlight.begin(), split.highlight.end());
|
|
175
186
|
allSo.insert(allSo.end(), split.showOnly.begin(), split.showOnly.end());
|
|
187
|
+
allDo.insert(allDo.end(), split.displayOnly.begin(), split.displayOnly.end());
|
|
176
188
|
|
|
177
189
|
std::vector<ColoredBody> bodies3d, sections2d;
|
|
178
190
|
for (const ColoredBody& c : split.foreground) {
|
|
@@ -251,6 +263,7 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
251
263
|
result.insert(result.end(), allBg.begin(), allBg.end());
|
|
252
264
|
result.insert(result.end(), allHi.begin(), allHi.end());
|
|
253
265
|
result.insert(result.end(), allSo.begin(), allSo.end());
|
|
266
|
+
result.insert(result.end(), allDo.begin(), allDo.end());
|
|
254
267
|
return result;
|
|
255
268
|
}
|
|
256
269
|
|
|
@@ -77,11 +77,23 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params,
|
|
|
77
77
|
// splitting/2D-merge logic.
|
|
78
78
|
struct RoleSplit {
|
|
79
79
|
std::vector<ColoredBody> background;
|
|
80
|
-
std::vector<ColoredBody> foreground; // role != Background && role != ShowOnly
|
|
80
|
+
std::vector<ColoredBody> foreground; // role != Background && role != ShowOnly, and not display-only
|
|
81
81
|
std::vector<ColoredBody> highlight; // the subset of `foreground` that's role == Highlight
|
|
82
82
|
std::vector<ColoredBody> showOnly;
|
|
83
|
+
// Bodies with no Manifold to operate on (an open polyhedron -- see
|
|
84
|
+
// ColoredBody::rawMesh). Split out for the same reason showOnly is:
|
|
85
|
+
// they must survive a CSG/hull/minkowski step untouched rather than be
|
|
86
|
+
// merged into it, since there is nothing to merge. Kept separate from
|
|
87
|
+
// `background` because they render as ordinary geometry, not as a
|
|
88
|
+
// translucent ghost.
|
|
89
|
+
std::vector<ColoredBody> displayOnly;
|
|
83
90
|
};
|
|
84
91
|
RoleSplit splitByRole(const std::vector<ColoredBody>& bodies);
|
|
92
|
+
|
|
93
|
+
// manifold::ToString(Manifold::Error) only exists under MANIFOLD_DEBUG --
|
|
94
|
+
// not enabled in this build -- so this mirrors it. Shared by import.cpp and
|
|
95
|
+
// primitives_3d.cpp, both of which report why a mesh wouldn't build.
|
|
96
|
+
std::string manifoldErrorName(manifold::Manifold::Error e);
|
|
85
97
|
std::optional<manifold::CrossSection> toCrossSection(const std::vector<ColoredBody>& bodies);
|
|
86
98
|
|
|
87
99
|
// Merges a statement's bodies into one (3D union, else 2D union, else an
|
|
@@ -49,29 +49,6 @@ LoadedMesh loadMeshByExt(const std::string& path, const std::string& ext) {
|
|
|
49
49
|
|
|
50
50
|
bool isMeshExt(const std::string& ext) { return ext == ".stl" || ext == ".obj" || ext == ".off" || ext == ".3mf"; }
|
|
51
51
|
|
|
52
|
-
// manifold::ToString(Manifold::Error) only exists under MANIFOLD_DEBUG --
|
|
53
|
-
// not enabled in this project's build -- so this mirrors it locally for the
|
|
54
|
-
// not-manifold warning message.
|
|
55
|
-
std::string manifoldErrorName(manifold::Manifold::Error e) {
|
|
56
|
-
switch (e) {
|
|
57
|
-
case manifold::Manifold::Error::NoError: return "NoError";
|
|
58
|
-
case manifold::Manifold::Error::NonFiniteVertex: return "NonFiniteVertex";
|
|
59
|
-
case manifold::Manifold::Error::NotManifold: return "NotManifold";
|
|
60
|
-
case manifold::Manifold::Error::VertexOutOfBounds: return "VertexOutOfBounds";
|
|
61
|
-
case manifold::Manifold::Error::PropertiesWrongLength: return "PropertiesWrongLength";
|
|
62
|
-
case manifold::Manifold::Error::MissingPositionProperties: return "MissingPositionProperties";
|
|
63
|
-
case manifold::Manifold::Error::MergeVectorsDifferentLengths: return "MergeVectorsDifferentLengths";
|
|
64
|
-
case manifold::Manifold::Error::MergeIndexOutOfBounds: return "MergeIndexOutOfBounds";
|
|
65
|
-
case manifold::Manifold::Error::TransformWrongLength: return "TransformWrongLength";
|
|
66
|
-
case manifold::Manifold::Error::RunIndexWrongLength: return "RunIndexWrongLength";
|
|
67
|
-
case manifold::Manifold::Error::FaceIDWrongLength: return "FaceIDWrongLength";
|
|
68
|
-
case manifold::Manifold::Error::InvalidConstruction: return "InvalidConstruction";
|
|
69
|
-
case manifold::Manifold::Error::ResultTooLarge: return "ResultTooLarge";
|
|
70
|
-
case manifold::Manifold::Error::InvalidTangents: return "InvalidTangents";
|
|
71
|
-
case manifold::Manifold::Error::Cancelled: return "Cancelled";
|
|
72
|
-
}
|
|
73
|
-
return "Unknown";
|
|
74
|
-
}
|
|
75
52
|
|
|
76
53
|
Value jsonToValue(const nlohmann::ordered_json& j) {
|
|
77
54
|
if (j.is_boolean()) return Value{j.get<bool>()};
|
|
@@ -135,6 +112,30 @@ Value meshToVnf(const LoadedMesh& mesh) {
|
|
|
135
112
|
|
|
136
113
|
} // namespace
|
|
137
114
|
|
|
115
|
+
// manifold::ToString(Manifold::Error) only exists under MANIFOLD_DEBUG --
|
|
116
|
+
// not enabled in this project's build -- so this mirrors it locally for the
|
|
117
|
+
// not-manifold warning message.
|
|
118
|
+
std::string manifoldErrorName(manifold::Manifold::Error e) {
|
|
119
|
+
switch (e) {
|
|
120
|
+
case manifold::Manifold::Error::NoError: return "NoError";
|
|
121
|
+
case manifold::Manifold::Error::NonFiniteVertex: return "NonFiniteVertex";
|
|
122
|
+
case manifold::Manifold::Error::NotManifold: return "NotManifold";
|
|
123
|
+
case manifold::Manifold::Error::VertexOutOfBounds: return "VertexOutOfBounds";
|
|
124
|
+
case manifold::Manifold::Error::PropertiesWrongLength: return "PropertiesWrongLength";
|
|
125
|
+
case manifold::Manifold::Error::MissingPositionProperties: return "MissingPositionProperties";
|
|
126
|
+
case manifold::Manifold::Error::MergeVectorsDifferentLengths: return "MergeVectorsDifferentLengths";
|
|
127
|
+
case manifold::Manifold::Error::MergeIndexOutOfBounds: return "MergeIndexOutOfBounds";
|
|
128
|
+
case manifold::Manifold::Error::TransformWrongLength: return "TransformWrongLength";
|
|
129
|
+
case manifold::Manifold::Error::RunIndexWrongLength: return "RunIndexWrongLength";
|
|
130
|
+
case manifold::Manifold::Error::FaceIDWrongLength: return "FaceIDWrongLength";
|
|
131
|
+
case manifold::Manifold::Error::InvalidConstruction: return "InvalidConstruction";
|
|
132
|
+
case manifold::Manifold::Error::ResultTooLarge: return "ResultTooLarge";
|
|
133
|
+
case manifold::Manifold::Error::InvalidTangents: return "InvalidTangents";
|
|
134
|
+
case manifold::Manifold::Error::Cancelled: return "Cancelled";
|
|
135
|
+
}
|
|
136
|
+
return "Unknown";
|
|
137
|
+
}
|
|
138
|
+
|
|
138
139
|
namespace {
|
|
139
140
|
|
|
140
141
|
Value contoursToValue(const std::vector<Contour2d>& contours) {
|
|
@@ -269,7 +270,15 @@ std::vector<ColoredBody> generateImport(Evaluator& ev, const CSGParams& params,
|
|
|
269
270
|
|
|
270
271
|
manifold::Manifold body(mesh);
|
|
271
272
|
if (body.Status() != manifold::Manifold::Error::NoError) {
|
|
272
|
-
|
|
273
|
+
// Same treatment as an open polyhedron() (see generatePolyhedron):
|
|
274
|
+
// keep the triangles so the file can still be LOOKED at. Previously
|
|
275
|
+
// this warned and then handed back an empty body, which was dropped
|
|
276
|
+
// downstream -- so a broken STL warned once and showed nothing,
|
|
277
|
+
// giving no way to see what was actually wrong with it.
|
|
278
|
+
ev.warn("import: mesh is not a closed solid (" + manifoldErrorName(body.Status()) +
|
|
279
|
+
"); drawing it as a surface, but it cannot take part in any CSG operation",
|
|
280
|
+
&node.position());
|
|
281
|
+
return {ev.tagDisplayOnly(std::move(mesh), node, params.at("color"))};
|
|
273
282
|
}
|
|
274
283
|
return {ev.tagGenerated(std::move(body), node, params.at("color"))};
|
|
275
284
|
}
|
{openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/src/builtins/primitives_3d.cpp
RENAMED
|
@@ -14,6 +14,45 @@ namespace oscadeval {
|
|
|
14
14
|
|
|
15
15
|
namespace {
|
|
16
16
|
bool isUndef(const Value& v) { return std::holds_alternative<std::monostate>(v); }
|
|
17
|
+
|
|
18
|
+
// Edges used by an odd number of triangles -- i.e. the mesh's open border.
|
|
19
|
+
// A closed solid has none; every edge is shared by exactly two faces.
|
|
20
|
+
//
|
|
21
|
+
// Counted on the UNDIRECTED edge (sorted endpoints) rather than the
|
|
22
|
+
// directed half-edge, so a hole reads as a hole regardless of winding:
|
|
23
|
+
// counting directed edges would also flag a merely back-to-front face,
|
|
24
|
+
// which builds into a perfectly valid solid and is not what this reports.
|
|
25
|
+
// Whether a mesh Manifold rejected is nonetheless safe to hand to a
|
|
26
|
+
// renderer. Only NotManifold qualifies: it means "the triangles are fine,
|
|
27
|
+
// they just don't close a solid", which is exactly the open-surface case
|
|
28
|
+
// worth drawing. Every other status (NonFiniteVertex above all, but also
|
|
29
|
+
// VertexOutOfBounds and friends) means the vertex data itself is broken --
|
|
30
|
+
// drawing NaN coordinates would poison the scene bounding box and send the
|
|
31
|
+
// camera auto-fit to infinity, which is worse than showing nothing. The
|
|
32
|
+
// explicit finite check is belt-and-braces, since nothing documents that a
|
|
33
|
+
// NotManifold mesh can't ALSO contain a NaN.
|
|
34
|
+
bool isDrawableFailure(const manifold::Manifold& body, const manifold::MeshGL& mesh) {
|
|
35
|
+
if (body.Status() != manifold::Manifold::Error::NotManifold) return false;
|
|
36
|
+
if (mesh.triVerts.empty()) return false;
|
|
37
|
+
return std::all_of(mesh.vertProperties.begin(), mesh.vertProperties.end(),
|
|
38
|
+
[](float v) { return std::isfinite(v); });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
size_t countBoundaryEdges(const manifold::MeshGL& mesh) {
|
|
42
|
+
std::map<std::pair<uint32_t, uint32_t>, int> uses;
|
|
43
|
+
for (size_t i = 0; i + 2 < mesh.triVerts.size(); i += 3) {
|
|
44
|
+
const uint32_t v[3] = {mesh.triVerts[i], mesh.triVerts[i + 1], mesh.triVerts[i + 2]};
|
|
45
|
+
for (int e = 0; e < 3; ++e) {
|
|
46
|
+
const uint32_t a = v[e], b = v[(e + 1) % 3];
|
|
47
|
+
++uses[{std::min(a, b), std::max(a, b)}];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
size_t open = 0;
|
|
51
|
+
for (const auto& [edge, count] : uses) {
|
|
52
|
+
if (count % 2 != 0) ++open;
|
|
53
|
+
}
|
|
54
|
+
return open;
|
|
55
|
+
}
|
|
17
56
|
} // namespace
|
|
18
57
|
|
|
19
58
|
// cube(size = 1, center = false) -- mirrors _resolve_cube/_generate_cube.
|
|
@@ -292,6 +331,31 @@ std::vector<ColoredBody> generatePolyhedron(Evaluator& ev, const CSGParams& para
|
|
|
292
331
|
mesh.triVerts.push_back(static_cast<uint32_t>(std::get<double>(t)));
|
|
293
332
|
}
|
|
294
333
|
manifold::Manifold body(mesh);
|
|
334
|
+
if (isDrawableFailure(body, mesh)) {
|
|
335
|
+
// An open surface -- faces that don't close the solid. Manifold
|
|
336
|
+
// signals that by returning an EMPTY body rather than throwing, so
|
|
337
|
+
// without this branch the polyhedron simply vanishes from the
|
|
338
|
+
// render with nothing said, leaving the author to guess which face
|
|
339
|
+
// they forgot.
|
|
340
|
+
//
|
|
341
|
+
// Report the boundary-edge count rather than Manifold's own
|
|
342
|
+
// "NotManifold" status string, which is actively misleading here: a
|
|
343
|
+
// closed mesh with reversed winding, non-manifold vertices or
|
|
344
|
+
// self-intersections builds perfectly well, and only an OPEN one
|
|
345
|
+
// reaches this branch. The count points straight at the problem.
|
|
346
|
+
ev.warn("polyhedron: mesh is not closed -- " + std::to_string(countBoundaryEdges(mesh)) +
|
|
347
|
+
" boundary edge(s); drawing it as a surface, but it cannot "
|
|
348
|
+
"take part in any CSG operation",
|
|
349
|
+
&node.position());
|
|
350
|
+
return {ev.tagDisplayOnly(std::move(mesh), node, params.at("color"))};
|
|
351
|
+
}
|
|
352
|
+
if (body.Status() != manifold::Manifold::Error::NoError) {
|
|
353
|
+
// Broken vertex data rather than merely-open topology (a NaN
|
|
354
|
+
// coordinate, an out-of-range index). Not drawable, so this keeps
|
|
355
|
+
// the old drop-it behaviour -- but says so, which it never used to.
|
|
356
|
+
ev.warn(std::string("polyhedron: ") + manifoldErrorName(body.Status()) + "; geometry discarded",
|
|
357
|
+
&node.position());
|
|
358
|
+
}
|
|
295
359
|
return {ev.tagGenerated(std::move(body), node, params.at("color"))};
|
|
296
360
|
}
|
|
297
361
|
|
|
@@ -61,6 +61,7 @@ std::vector<ColoredBody> generateHull(Evaluator&, const CSGParams&, const std::v
|
|
|
61
61
|
result.insert(result.end(), split.background.begin(), split.background.end());
|
|
62
62
|
result.insert(result.end(), split.highlight.begin(), split.highlight.end());
|
|
63
63
|
result.insert(result.end(), split.showOnly.begin(), split.showOnly.end());
|
|
64
|
+
result.insert(result.end(), split.displayOnly.begin(), split.displayOnly.end());
|
|
64
65
|
return result;
|
|
65
66
|
}
|
|
66
67
|
|
|
@@ -89,6 +90,7 @@ std::vector<ColoredBody> generateMinkowski(Evaluator& ev, const CSGParams&, cons
|
|
|
89
90
|
passthrough.insert(passthrough.end(), split.background.begin(), split.background.end());
|
|
90
91
|
passthrough.insert(passthrough.end(), split.highlight.begin(), split.highlight.end());
|
|
91
92
|
passthrough.insert(passthrough.end(), split.showOnly.begin(), split.showOnly.end());
|
|
93
|
+
passthrough.insert(passthrough.end(), split.displayOnly.begin(), split.displayOnly.end());
|
|
92
94
|
|
|
93
95
|
if (bodies3d.empty()) return passthrough;
|
|
94
96
|
if (bodies3d.size() == 1) {
|
|
@@ -110,4 +110,27 @@ ColoredBody Evaluator::tagGenerated(manifold::Manifold body, const oscad::ASTNod
|
|
|
110
110
|
return cb;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
ColoredBody Evaluator::tagDisplayOnly(manifold::MeshGL mesh, const oscad::ASTNode& node, const Value& colorValue) {
|
|
114
|
+
const std::optional<std::array<float, 4>> color = valueToColor(colorValue);
|
|
115
|
+
|
|
116
|
+
// A Manifold that failed to build carries no run IDs, so reserve one
|
|
117
|
+
// and describe the whole soup as a single run. ReserveIDs() draws from
|
|
118
|
+
// the same global counter Manifold hands to real bodies, so an ID
|
|
119
|
+
// minted here can never collide with one of theirs.
|
|
120
|
+
const uint32_t originalId = manifold::Manifold::ReserveIDs(1);
|
|
121
|
+
mesh.runOriginalID = {originalId};
|
|
122
|
+
mesh.runIndex = {0, static_cast<uint32_t>(mesh.triVerts.size())};
|
|
123
|
+
idToNode[originalId] = &node;
|
|
124
|
+
idToColor[originalId] = color;
|
|
125
|
+
|
|
126
|
+
ColoredBody cb;
|
|
127
|
+
// Left set-but-empty rather than nullopt: consumers dereference
|
|
128
|
+
// cb.body unconditionally, and an empty Manifold is also the honest
|
|
129
|
+
// answer to "what solid is this?" -- there isn't one.
|
|
130
|
+
cb.body = manifold::Manifold();
|
|
131
|
+
cb.color = color;
|
|
132
|
+
cb.rawMesh = std::move(mesh);
|
|
133
|
+
return cb;
|
|
134
|
+
}
|
|
135
|
+
|
|
113
136
|
} // namespace oscadeval
|
{openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/tests/test_import_export.cpp
RENAMED
|
@@ -137,7 +137,14 @@ TEST(ImportModuleContext, NonManifoldMeshWarns) {
|
|
|
137
137
|
}
|
|
138
138
|
std::string lastWarning;
|
|
139
139
|
Evaluated e = evalSrc("import(\"" + path.string() + "\");", [&](const std::string& msg) { lastWarning = msg; });
|
|
140
|
-
EXPECT_NE(lastWarning.find("import: mesh is not
|
|
140
|
+
EXPECT_NE(lastWarning.find("import: mesh is not a closed solid"), std::string::npos);
|
|
141
|
+
// The triangle is now handed back for display rather than dropped: a
|
|
142
|
+
// file that warns once and then shows nothing gives no way to see what
|
|
143
|
+
// is actually wrong with it. It carries no Manifold, so it still can't
|
|
144
|
+
// take part in a CSG operation.
|
|
145
|
+
ASSERT_EQ(e.bodies.size(), 1u);
|
|
146
|
+
EXPECT_TRUE(e.bodies[0].isDisplayOnly());
|
|
147
|
+
EXPECT_EQ(e.bodies[0].rawMesh->triVerts.size(), 3u);
|
|
141
148
|
std::filesystem::remove(path);
|
|
142
149
|
}
|
|
143
150
|
|
|
@@ -181,3 +181,95 @@ TEST(Primitives2d, PolygonWithPathsSelectsIndexedContour) {
|
|
|
181
181
|
Evaluated e = evalSrc("polygon(points=[[0,0],[2,0],[2,2],[0,2]], paths=[[0,1,2,3]]);");
|
|
182
182
|
EXPECT_NEAR(e.bodies[0].section->Area(), 4.0, 1e-9);
|
|
183
183
|
}
|
|
184
|
+
|
|
185
|
+
// -- open (non-closed) polyhedron: display-only ---------------------------
|
|
186
|
+
|
|
187
|
+
namespace {
|
|
188
|
+
// A cube with the -x face omitted: five quads, so four boundary edges.
|
|
189
|
+
constexpr const char* kOpenCube =
|
|
190
|
+
"polyhedron(points=[[0,0,0],[10,0,0],[10,10,0],[0,10,0],"
|
|
191
|
+
" [0,0,10],[10,0,10],[10,10,10],[0,10,10]],"
|
|
192
|
+
" faces=[[0,1,2,3],[4,7,6,5],[0,4,5,1],[1,5,6,2],[2,6,7,3]]);";
|
|
193
|
+
} // namespace
|
|
194
|
+
|
|
195
|
+
// Manifold cannot represent an open surface, but silently rendering nothing
|
|
196
|
+
// left no way to tell a broken polyhedron from a missing one. The triangles
|
|
197
|
+
// are kept for display instead, tagged so nothing tries to CSG them.
|
|
198
|
+
TEST(Polyhedron, OpenMeshIsKeptForDisplayAndWarns) {
|
|
199
|
+
std::string warning;
|
|
200
|
+
Evaluated e = evalSrc(kOpenCube, [&](const std::string& m) { warning = m; });
|
|
201
|
+
|
|
202
|
+
ASSERT_EQ(e.bodies.size(), 1u);
|
|
203
|
+
EXPECT_TRUE(e.bodies[0].isDisplayOnly());
|
|
204
|
+
EXPECT_TRUE(e.bodies[0].body->IsEmpty()); // no solid, by definition
|
|
205
|
+
EXPECT_EQ(e.bodies[0].rawMesh->triVerts.size(), 10u * 3u); // 5 quads -> 10 tris
|
|
206
|
+
|
|
207
|
+
EXPECT_NE(warning.find("not closed"), std::string::npos) << warning;
|
|
208
|
+
EXPECT_NE(warning.find("4 boundary edge"), std::string::npos) << warning;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// The originalID is what maps a picked triangle back to its source line, so
|
|
212
|
+
// a display-only body has to carry one or clicking it would select nothing
|
|
213
|
+
// -- precisely when a user most wants to be shown the offending code.
|
|
214
|
+
TEST(Polyhedron, OpenMeshCarriesAnOriginalIdForPicking) {
|
|
215
|
+
Evaluated e = evalSrc(kOpenCube);
|
|
216
|
+
ASSERT_EQ(e.bodies.size(), 1u);
|
|
217
|
+
const manifold::MeshGL& mesh = *e.bodies[0].rawMesh;
|
|
218
|
+
ASSERT_EQ(mesh.runOriginalID.size(), 1u);
|
|
219
|
+
EXPECT_EQ(e.ev.idToNode.count(mesh.runOriginalID[0]), 1u);
|
|
220
|
+
ASSERT_EQ(mesh.runIndex.size(), 2u);
|
|
221
|
+
EXPECT_EQ(mesh.runIndex[1], mesh.triVerts.size());
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// A closed mesh is still a solid however badly it's wound or built -- only
|
|
225
|
+
// an OPEN one takes the display-only path. Manifold's own status name for
|
|
226
|
+
// that case ("NotManifold") reads as though it covers these too; it doesn't.
|
|
227
|
+
TEST(Polyhedron, ClosedButUglyMeshesStillBuildSolids) {
|
|
228
|
+
// All faces reversed (inside-out).
|
|
229
|
+
Evaluated inverted = evalSrc(
|
|
230
|
+
"polyhedron(points=[[0,0,0],[10,0,0],[10,10,0],[0,10,0],"
|
|
231
|
+
" [0,0,10],[10,0,10],[10,10,10],[0,10,10]],"
|
|
232
|
+
" faces=[[3,2,1,0],[5,6,7,4],[1,5,4,0],[2,6,5,1],[3,7,6,2],[0,4,7,3]]);");
|
|
233
|
+
ASSERT_EQ(inverted.bodies.size(), 1u);
|
|
234
|
+
EXPECT_FALSE(inverted.bodies[0].isDisplayOnly());
|
|
235
|
+
|
|
236
|
+
// Two tetrahedra meeting at a single (non-manifold) vertex.
|
|
237
|
+
Evaluated pinched = evalSrc(
|
|
238
|
+
"polyhedron(points=[[0,0,0],[10,0,0],[0,10,0],[0,0,10],"
|
|
239
|
+
" [0,0,0],[-10,0,0],[0,-10,0],[0,0,-10]],"
|
|
240
|
+
" faces=[[0,2,1],[0,1,3],[1,2,3],[0,3,2],"
|
|
241
|
+
" [4,6,5],[4,5,7],[5,6,7],[4,7,6]]);");
|
|
242
|
+
ASSERT_EQ(pinched.bodies.size(), 1u);
|
|
243
|
+
EXPECT_FALSE(pinched.bodies[0].isDisplayOnly());
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// A NaN coordinate is NOT drawable: it would poison the scene bounding box
|
|
247
|
+
// and send a renderer's camera auto-fit to infinity. Such a mesh keeps the
|
|
248
|
+
// old drop-it behaviour -- but now says so instead of vanishing mutely.
|
|
249
|
+
TEST(Polyhedron, NonFiniteVertexIsDiscardedNotDisplayed) {
|
|
250
|
+
std::string warning;
|
|
251
|
+
Evaluated e = evalSrc("polyhedron(points=[[0,0,0],[2,0,0],[0,2,0],[0/0,0,2]],"
|
|
252
|
+
" faces=[[0,1,2],[0,3,1],[0,2,3],[1,3,2]]);",
|
|
253
|
+
[&](const std::string& m) { warning = m; });
|
|
254
|
+
for (const ColoredBody& b : e.bodies) EXPECT_FALSE(b.isDisplayOnly());
|
|
255
|
+
EXPECT_NE(warning.find("NonFiniteVertex"), std::string::npos) << warning;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// It has no Manifold, so a boolean would have nothing to operate on. It is
|
|
259
|
+
// pulled aside like a `%` body and re-joined afterwards, leaving its valid
|
|
260
|
+
// siblings to merge normally.
|
|
261
|
+
TEST(Polyhedron, OpenMeshIsExcludedFromCsgButSurvivesIt) {
|
|
262
|
+
Evaluated e = evalSrc(std::string("union() { translate([50,0,0]) cube(4); ") + kOpenCube + " }");
|
|
263
|
+
ASSERT_EQ(e.bodies.size(), 2u);
|
|
264
|
+
|
|
265
|
+
int solids = 0, displayOnly = 0;
|
|
266
|
+
for (const ColoredBody& b : e.bodies) {
|
|
267
|
+
if (b.isDisplayOnly()) ++displayOnly;
|
|
268
|
+
else if (b.body && !b.body->IsEmpty()) {
|
|
269
|
+
++solids;
|
|
270
|
+
EXPECT_NEAR(b.body->Volume(), 64.0, 1e-6); // the cube, unharmed
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
EXPECT_EQ(solids, 1);
|
|
274
|
+
EXPECT_EQ(displayOnly, 1);
|
|
275
|
+
}
|
|
File without changes
|
{openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.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-0.14.0 → openscad_cpp_evaluator-0.15.0}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.15.0}/examples/manifold_cache_reuse.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-0.14.0 → openscad_cpp_evaluator-0.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
|