openscad-cpp-evaluator 1.23.1__tar.gz → 1.24.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.23.1 → openscad_cpp_evaluator-1.24.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/evaluator.hpp +12 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +17 -3
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/CMakeLists.txt +34 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/function_builtins.cpp +0 -32
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/primitives_3d.cpp +49 -6
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/topology.cpp +0 -12
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/csg_generate.cpp +33 -3
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/expr_eval.cpp +7 -3
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/manifold_cache.cpp +3 -3
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/value.cpp +0 -30
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/CMakeLists.txt +4 -1
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_csg_tree.cpp +49 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_manifold_cache.cpp +63 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/README.md +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/uv.lock +0 -0
|
@@ -398,6 +398,14 @@ public:
|
|
|
398
398
|
// than anything reentrancy-aware, since generateTreeImpl recurses
|
|
399
399
|
// depth-first on one thread.
|
|
400
400
|
const oscad::Position* generateWarnEntry = nullptr;
|
|
401
|
+
// Non-null while generateTreeImpl() is generating a subtree whose result
|
|
402
|
+
// it intends to cache: warn() appends each formatted line here as well as
|
|
403
|
+
// emitting it, so the entry can replay them on a later hit. Saved and
|
|
404
|
+
// restored around each node rather than left set, and the inner vector is
|
|
405
|
+
// merged into the outer one on the way out, so a parent's entry carries
|
|
406
|
+
// everything its whole subtree said -- which is what a parent-level hit
|
|
407
|
+
// has to reproduce, since it skips all of it. See ManifoldCache.
|
|
408
|
+
std::vector<std::string>* warnCapture = nullptr;
|
|
401
409
|
// The same republish for CSGNode::callChain, read by tagGenerated to
|
|
402
410
|
// fill idToCallChain.
|
|
403
411
|
uint32_t generateCallChain = kNoCallChain;
|
|
@@ -530,6 +538,10 @@ public:
|
|
|
530
538
|
// Public: builtins/import.cpp's not-manifold warning is emitted from a
|
|
531
539
|
// free function, same reasoning as tagGenerated()/builtinChildren().
|
|
532
540
|
void warn(const std::string& message, const oscad::Position* position);
|
|
541
|
+
// Hands one already-formatted warning line to echoFn_, recording it in
|
|
542
|
+
// warnCapture first when one is active. Every warning path goes through
|
|
543
|
+
// here, including a ManifoldCache hit replaying a cached line.
|
|
544
|
+
void emitWarning(const std::string& formatted);
|
|
533
545
|
|
|
534
546
|
// Applies OpenSCAD's mixed-2D/3D rules to a node's children just
|
|
535
547
|
// before its GenerateFn runs -- see csg_generate.cpp.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include "openscad_cpp_evaluator/csg_node.hpp"
|
|
4
4
|
|
|
5
5
|
#include <mutex>
|
|
6
|
+
#include <vector>
|
|
6
7
|
#include <optional>
|
|
7
8
|
#include <string>
|
|
8
9
|
#include <unordered_map>
|
|
@@ -22,15 +23,28 @@ namespace oscadeval {
|
|
|
22
23
|
// threading.Lock -- a host may run renders/evaluates on a background
|
|
23
24
|
// thread while another operation reads/clears the same cache). Mirrors
|
|
24
25
|
// the reference's ManifoldCache class.
|
|
26
|
+
// What one cache entry holds. The warnings matter as much as the bodies:
|
|
27
|
+
// a hit skips the whole subtree's GenerateFn, and every generate-time
|
|
28
|
+
// diagnostic is raised *inside* one of those (polyhedron's "mesh is not
|
|
29
|
+
// closed", import()'s failures, the dimension rules). Cached without them,
|
|
30
|
+
// a second render of unchanged source silently dropped every warning the
|
|
31
|
+
// first one raised, so a real defect looked intermittent and the author
|
|
32
|
+
// went hunting for a phantom. A cache has to be transparent; that includes
|
|
33
|
+
// what it says, not only what it draws. See BelfrySCAD issue #521.
|
|
34
|
+
struct CachedSubtree {
|
|
35
|
+
std::vector<ColoredBody> bodies;
|
|
36
|
+
std::vector<std::string> warnings; // already formatted, replayed verbatim
|
|
37
|
+
};
|
|
38
|
+
|
|
25
39
|
class ManifoldCache {
|
|
26
40
|
public:
|
|
27
|
-
std::optional<
|
|
28
|
-
void put(std::string key, std::vector<ColoredBody> bodies);
|
|
41
|
+
std::optional<CachedSubtree> get(const std::string& key) const;
|
|
42
|
+
void put(std::string key, std::vector<ColoredBody> bodies, std::vector<std::string> warnings);
|
|
29
43
|
void clear();
|
|
30
44
|
|
|
31
45
|
private:
|
|
32
46
|
mutable std::mutex mutex_;
|
|
33
|
-
std::unordered_map<std::string,
|
|
47
|
+
std::unordered_map<std::string, CachedSubtree> entries_;
|
|
34
48
|
};
|
|
35
49
|
|
|
36
50
|
// Structural content-hash key for `node`, used by generateTree()'s
|
|
@@ -69,3 +69,37 @@ target_link_libraries(openscad_cpp_evaluator PRIVATE linenoise freetype harfbuzz
|
|
|
69
69
|
target_compile_options(openscad_cpp_evaluator PRIVATE
|
|
70
70
|
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall;-Wextra>
|
|
71
71
|
)
|
|
72
|
+
|
|
73
|
+
# -Wall -Wextra above is about OUR code, but two TUs pull a vendored header
|
|
74
|
+
# in wholesale and inherit its warnings: 27 from Boost.Polygon's voronoi
|
|
75
|
+
# headers and 9 from stb_image_write's implementation, against 5 that were
|
|
76
|
+
# real. Silenced per source file, per warning.
|
|
77
|
+
#
|
|
78
|
+
# Deliberately NOT -isystem, which looks like the tidier fix and is a trap:
|
|
79
|
+
# clang searches -isystem AFTER /usr/local/include, so a Homebrew Boost
|
|
80
|
+
# 1.90 silently won over the pinned 1.86 (measured, not assumed). Keeping
|
|
81
|
+
# -I keeps the fetched copy winning.
|
|
82
|
+
include(CheckCXXCompilerFlag)
|
|
83
|
+
foreach(_w deprecated-enum-float-conversion missing-field-initializers deprecated-declarations)
|
|
84
|
+
check_cxx_compiler_flag("-Wno-${_w}" OSCAD_HAS_WNO_${_w})
|
|
85
|
+
endforeach()
|
|
86
|
+
|
|
87
|
+
if(OSCAD_HAS_WNO_deprecated-enum-float-conversion)
|
|
88
|
+
# <boost/polygon/voronoi.hpp> does floating-point arithmetic on an
|
|
89
|
+
# unnamed enum, deprecated in C++20.
|
|
90
|
+
set_source_files_properties(builtins/roof.cpp PROPERTIES
|
|
91
|
+
COMPILE_OPTIONS "-Wno-deprecated-enum-float-conversion")
|
|
92
|
+
endif()
|
|
93
|
+
|
|
94
|
+
# zip_stored.cpp defines STB_IMAGE_WRITE_IMPLEMENTATION, so stb's C compiles
|
|
95
|
+
# as ours: `= { 0 }` partial initializers, and one sprintf().
|
|
96
|
+
set(_stb_quiet "")
|
|
97
|
+
if(OSCAD_HAS_WNO_missing-field-initializers)
|
|
98
|
+
list(APPEND _stb_quiet "-Wno-missing-field-initializers")
|
|
99
|
+
endif()
|
|
100
|
+
if(OSCAD_HAS_WNO_deprecated-declarations)
|
|
101
|
+
list(APPEND _stb_quiet "-Wno-deprecated-declarations")
|
|
102
|
+
endif()
|
|
103
|
+
if(_stb_quiet)
|
|
104
|
+
set_source_files_properties(zip_stored.cpp PROPERTIES COMPILE_OPTIONS "${_stb_quiet}")
|
|
105
|
+
endif()
|
{openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/function_builtins.cpp
RENAMED
|
@@ -837,38 +837,6 @@ Value builtinFontmetrics(Evaluator& ev, const CallArgs& args) {
|
|
|
837
837
|
});
|
|
838
838
|
}
|
|
839
839
|
|
|
840
|
-
// Take only scalar numbers, mapped to how many leading positional
|
|
841
|
-
// arguments must each actually BE a number. Anything else there (undef, a
|
|
842
|
-
// string, a list, a bool, an object) is a type error yielding undef, and
|
|
843
|
-
// so is supplying fewer arguments than the arity -- matching the
|
|
844
|
-
// reference, which rejects the call outright rather than coercing.
|
|
845
|
-
//
|
|
846
|
-
// This has to be checked up front rather than left to each case below:
|
|
847
|
-
// toDoubleLenient() silently turns undef/string/list into 0.0, which
|
|
848
|
-
// would make `cos(misspelled_var)` quietly 1 instead of undef, and a
|
|
849
|
-
// typo'd variable then produces plausible-looking geometry instead of an
|
|
850
|
-
// obvious failure. Arity is deliberately a floor, not an exact match --
|
|
851
|
-
// the reference also rejects EXTRA arguments, but tightening that too
|
|
852
|
-
// risks breaking working library code for no correctness gain here.
|
|
853
|
-
const std::unordered_map<std::string, size_t>& scalarNumericArity() {
|
|
854
|
-
static const std::unordered_map<std::string, size_t> arity = {
|
|
855
|
-
{"abs", 1}, {"sign", 1}, {"ceil", 1}, {"floor", 1}, {"round", 1}, {"sqrt", 1},
|
|
856
|
-
{"ln", 1}, {"log", 1}, {"exp", 1}, {"sin", 1}, {"cos", 1}, {"tan", 1},
|
|
857
|
-
{"asin", 1}, {"acos", 1}, {"atan", 1}, {"atan2", 2}, {"pow", 2}, {"rands", 3},
|
|
858
|
-
};
|
|
859
|
-
return arity;
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
// Numeric functions that legitimately take a LIST argument, so the
|
|
863
|
-
// all-arguments-must-be-numbers rule above can't apply -- each validates
|
|
864
|
-
// its own operands, and only needs the bool case caught here (Value's
|
|
865
|
-
// bool and double are distinct alternatives, but the reference rejects
|
|
866
|
-
// `max(true, 1)` as a type error rather than treating true as 1).
|
|
867
|
-
const std::unordered_set<std::string>& numericOnlyNames() {
|
|
868
|
-
static const std::unordered_set<std::string> names = {"max", "min", "norm", "cross"};
|
|
869
|
-
return names;
|
|
870
|
-
}
|
|
871
|
-
|
|
872
840
|
} // namespace
|
|
873
841
|
|
|
874
842
|
bool isBuiltinFunctionName(const std::string& name) {
|
{openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/src/builtins/primitives_3d.cpp
RENAMED
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
#include <cstdint>
|
|
12
12
|
#include <map>
|
|
13
13
|
#include <numbers>
|
|
14
|
+
#include <optional>
|
|
14
15
|
#include <set>
|
|
16
|
+
#include <string>
|
|
17
|
+
#include <utility>
|
|
15
18
|
|
|
16
19
|
namespace oscadeval {
|
|
17
20
|
|
|
@@ -42,8 +45,18 @@ bool isDrawableFailure(const manifold::Manifold& body, const M& mesh) {
|
|
|
42
45
|
[](float v) { return std::isfinite(v); });
|
|
43
46
|
}
|
|
44
47
|
|
|
48
|
+
struct BoundaryEdges {
|
|
49
|
+
size_t count = 0;
|
|
50
|
+
// Vertex indices of one representative open edge, or nullopt when the
|
|
51
|
+
// mesh is closed. A count alone is enough on a hand-written face list,
|
|
52
|
+
// where you can just read it; it is useless on generated geometry --
|
|
53
|
+
// three bad edges in a few thousand triangles cannot be found by eye,
|
|
54
|
+
// which is what happened in BelfrySCAD #521 / issue #187.
|
|
55
|
+
std::optional<std::pair<uint32_t, uint32_t>> first;
|
|
56
|
+
};
|
|
57
|
+
|
|
45
58
|
template <typename M>
|
|
46
|
-
|
|
59
|
+
BoundaryEdges findBoundaryEdges(const M& mesh) {
|
|
47
60
|
std::map<std::pair<uint32_t, uint32_t>, int> uses;
|
|
48
61
|
for (size_t i = 0; i + 2 < mesh.triVerts.size(); i += 3) {
|
|
49
62
|
const uint32_t v[3] = {static_cast<uint32_t>(mesh.triVerts[i]),
|
|
@@ -54,11 +67,34 @@ size_t countBoundaryEdges(const M& mesh) {
|
|
|
54
67
|
++uses[{std::min(a, b), std::max(a, b)}];
|
|
55
68
|
}
|
|
56
69
|
}
|
|
57
|
-
|
|
70
|
+
BoundaryEdges out;
|
|
71
|
+
// std::map iterates in vertex-index order, which is arbitrary from the
|
|
72
|
+
// author's point of view but DETERMINISTIC: the same mesh names the same
|
|
73
|
+
// edge on every run. That matters more than which edge gets picked --
|
|
74
|
+
// an identifier that moves between renders is worse than no identifier.
|
|
75
|
+
// A cluster of open edges is nearly always one hole, so the first is
|
|
76
|
+
// usually representative of the rest.
|
|
58
77
|
for (const auto& [edge, count] : uses) {
|
|
59
|
-
if (count % 2
|
|
78
|
+
if (count % 2 == 0) continue;
|
|
79
|
+
++out.count;
|
|
80
|
+
if (!out.first) out.first = edge;
|
|
60
81
|
}
|
|
61
|
-
return
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// "[1, 2.5, 0] - [1, 3, 0]" for one edge, using the same number formatting
|
|
86
|
+
// echo() uses, so a coordinate can be pasted straight back into a script.
|
|
87
|
+
template <typename M>
|
|
88
|
+
std::string describeEdge(const M& mesh, std::pair<uint32_t, uint32_t> edge) {
|
|
89
|
+
const size_t stride = mesh.numProp > 0 ? static_cast<size_t>(mesh.numProp) : 3;
|
|
90
|
+
auto point = [&](uint32_t v) {
|
|
91
|
+
const size_t base = static_cast<size_t>(v) * stride;
|
|
92
|
+
if (base + 2 >= mesh.vertProperties.size()) return std::string("?");
|
|
93
|
+
return "[" + formatNumber(static_cast<double>(mesh.vertProperties[base])) + ", " +
|
|
94
|
+
formatNumber(static_cast<double>(mesh.vertProperties[base + 1])) + ", " +
|
|
95
|
+
formatNumber(static_cast<double>(mesh.vertProperties[base + 2])) + "]";
|
|
96
|
+
};
|
|
97
|
+
return point(edge.first) + " - " + point(edge.second);
|
|
62
98
|
}
|
|
63
99
|
} // namespace
|
|
64
100
|
|
|
@@ -810,8 +846,15 @@ std::vector<ColoredBody> generatePolyhedron(Evaluator& ev, const CSGParams& para
|
|
|
810
846
|
// self-intersections builds perfectly well, and only an OPEN one
|
|
811
847
|
// reaches this branch. The count points straight at the problem.
|
|
812
848
|
if (!ev.insideHull) {
|
|
813
|
-
|
|
814
|
-
|
|
849
|
+
const BoundaryEdges open = findBoundaryEdges(mesh);
|
|
850
|
+
// Name one of them. Where the hole IS is the only part of this
|
|
851
|
+
// message an author can act on; the count alone just says to go
|
|
852
|
+
// looking, across the whole mesh.
|
|
853
|
+
const std::string where =
|
|
854
|
+
open.first ? ", first at " + describeEdge(mesh, *open.first) : std::string();
|
|
855
|
+
ev.warn("polyhedron: mesh is not closed -- " + std::to_string(open.count) +
|
|
856
|
+
" boundary edge(s)" + where +
|
|
857
|
+
"; drawing it as a surface. hull() can still "
|
|
815
858
|
"use its points, but it cannot take part in union/difference/intersection",
|
|
816
859
|
&node.position());
|
|
817
860
|
}
|
|
@@ -621,18 +621,6 @@ double bandDistance(double v, double lo, double hi, bool invert) {
|
|
|
621
621
|
return invert ? -d : d;
|
|
622
622
|
}
|
|
623
623
|
|
|
624
|
-
std::optional<std::array<double, 3>> readVec3(const Value& v) {
|
|
625
|
-
const ListPtr* l = std::get_if<ListPtr>(&v);
|
|
626
|
-
if (!l || !*l || (*l)->items.size() != 3) return std::nullopt;
|
|
627
|
-
std::array<double, 3> out{};
|
|
628
|
-
for (size_t i = 0; i < 3; ++i) {
|
|
629
|
-
const double* d = std::get_if<double>(&(*l)->items[i]);
|
|
630
|
-
if (!d || !std::isfinite(*d)) return std::nullopt;
|
|
631
|
-
out[i] = *d;
|
|
632
|
-
}
|
|
633
|
-
return out;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
624
|
} // namespace
|
|
637
625
|
|
|
638
626
|
// -- 2D: marching squares --------------------------------------------------
|
|
@@ -58,9 +58,16 @@ std::vector<ColoredBody> Evaluator::generateTreeImpl(const std::vector<CSGNode*>
|
|
|
58
58
|
// skipped. See CSGNode::keyHasClosure.
|
|
59
59
|
if (node.keyHasClosure) key.reset();
|
|
60
60
|
}
|
|
61
|
-
std::optional<
|
|
61
|
+
std::optional<CachedSubtree> cached = key ? manifoldCache_->get(*key) : std::nullopt;
|
|
62
62
|
if (cached) {
|
|
63
|
-
node.bodies = std::move(
|
|
63
|
+
node.bodies = std::move(cached->bodies);
|
|
64
|
+
// Replay what generating this subtree said the first time. A hit
|
|
65
|
+
// runs none of it again, so without this the diagnostics simply
|
|
66
|
+
// disappear on every render after the first -- which is how a
|
|
67
|
+
// permanently-open polyhedron came to look like an intermittent
|
|
68
|
+
// one (BelfrySCAD #521). Goes through emitWarning so an enclosing
|
|
69
|
+
// capture records them too, exactly as a fresh generate would.
|
|
70
|
+
for (const std::string& w : cached->warnings) emitWarning(w);
|
|
64
71
|
// Skipped entirely while measuring: restampCachedIds writes
|
|
65
72
|
// idToNode/idToColor, and geometry that is about to be discarded
|
|
66
73
|
// has no click-to-source identity worth recording. See
|
|
@@ -83,6 +90,23 @@ std::vector<ColoredBody> Evaluator::generateTreeImpl(const std::vector<CSGNode*>
|
|
|
83
90
|
// inside this hull.
|
|
84
91
|
const bool savedInsideHull = insideHull;
|
|
85
92
|
if (node.isBuiltin && node.kind == "hull") insideHull = true;
|
|
93
|
+
// Collect everything this subtree warns about, so put() below can
|
|
94
|
+
// store it with the bodies. Only worth doing when the result is
|
|
95
|
+
// actually cacheable -- an uncacheable node (rands() taint, a
|
|
96
|
+
// closure in the key) regenerates every time and warns every time
|
|
97
|
+
// by itself.
|
|
98
|
+
std::vector<std::string> subtreeWarnings;
|
|
99
|
+
// RAII, unlike the plain save/restore insideHull and
|
|
100
|
+
// generateWarnEntry use above: those restore a value, this one
|
|
101
|
+
// restores a POINTER to a stack vector. An EvalError thrown out
|
|
102
|
+
// of a GenerateFn would otherwise leave warnCapture dangling at
|
|
103
|
+
// a destroyed vector for any warning raised afterwards.
|
|
104
|
+
struct CaptureGuard {
|
|
105
|
+
Evaluator& ev;
|
|
106
|
+
std::vector<std::string>* saved;
|
|
107
|
+
~CaptureGuard() { ev.warnCapture = saved; }
|
|
108
|
+
} captureGuard{*this, warnCapture};
|
|
109
|
+
if (key) warnCapture = &subtreeWarnings;
|
|
86
110
|
generateTreeImpl(childPtrs);
|
|
87
111
|
insideHull = savedInsideHull;
|
|
88
112
|
|
|
@@ -111,12 +135,18 @@ std::vector<ColoredBody> Evaluator::generateTreeImpl(const std::vector<CSGNode*>
|
|
|
111
135
|
node.bodies = flattenCsgTree(node.children);
|
|
112
136
|
}
|
|
113
137
|
if (key) {
|
|
138
|
+
warnCapture = captureGuard.saved;
|
|
139
|
+
// Merge inward-out: an ancestor still capturing must end up
|
|
140
|
+
// holding this subtree's lines too, since a hit at ITS level
|
|
141
|
+
// skips everything down here.
|
|
142
|
+
if (warnCapture != nullptr)
|
|
143
|
+
warnCapture->insert(warnCapture->end(), subtreeWarnings.begin(), subtreeWarnings.end());
|
|
114
144
|
// The geometry itself is still cached while measuring --
|
|
115
145
|
// cacheKey is content-addressed, so the real render can
|
|
116
146
|
// legitimately reuse it. Only the PRODUCER attribution is
|
|
117
147
|
// suppressed: a node that gets discarded must never be
|
|
118
148
|
// recorded as the origin of geometry a later render draws.
|
|
119
|
-
manifoldCache_->put(*key, node.bodies);
|
|
149
|
+
manifoldCache_->put(*key, node.bodies, std::move(subtreeWarnings));
|
|
120
150
|
if (!measuring_) cacheProducer_[*key] = node.node;
|
|
121
151
|
}
|
|
122
152
|
// The children's bodies have been consumed (by the dispatch above,
|
|
@@ -19,7 +19,6 @@ namespace oscadeval {
|
|
|
19
19
|
namespace {
|
|
20
20
|
|
|
21
21
|
bool isNumber(const Value& v) { return std::holds_alternative<double>(v); }
|
|
22
|
-
bool isBoolValue(const Value& v) { return std::holds_alternative<bool>(v); }
|
|
23
22
|
|
|
24
23
|
// Converts a Value to the truncated-to-int64 form real OpenSCAD's own
|
|
25
24
|
// Value::toInt64() uses for bitwise operations (Value.cc, PR #4833:
|
|
@@ -102,10 +101,15 @@ void Evaluator::warn(const std::string& message, const oscad::Position* position
|
|
|
102
101
|
if (!sameSpot) {
|
|
103
102
|
out += ", from " + generateWarnEntry->origin + ", line " + std::to_string(generateWarnEntry->line);
|
|
104
103
|
}
|
|
105
|
-
|
|
104
|
+
emitWarning(out);
|
|
106
105
|
return;
|
|
107
106
|
}
|
|
108
|
-
|
|
107
|
+
emitWarning(formatWarning(message, position, callStack_));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
void Evaluator::emitWarning(const std::string& formatted) {
|
|
111
|
+
if (warnCapture != nullptr) warnCapture->push_back(formatted);
|
|
112
|
+
if (echoFn_) echoFn_(formatted);
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
const oscad::Identifier* Evaluator::undefProbeTarget(const oscad::PrimaryCall& call) {
|
|
@@ -7,16 +7,16 @@
|
|
|
7
7
|
|
|
8
8
|
namespace oscadeval {
|
|
9
9
|
|
|
10
|
-
std::optional<
|
|
10
|
+
std::optional<CachedSubtree> ManifoldCache::get(const std::string& key) const {
|
|
11
11
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
12
12
|
auto it = entries_.find(key);
|
|
13
13
|
if (it == entries_.end()) return std::nullopt;
|
|
14
14
|
return it->second;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
void ManifoldCache::put(std::string key, std::vector<ColoredBody> bodies) {
|
|
17
|
+
void ManifoldCache::put(std::string key, std::vector<ColoredBody> bodies, std::vector<std::string> warnings) {
|
|
18
18
|
std::lock_guard<std::mutex> lock(mutex_);
|
|
19
|
-
entries_[std::move(key)] = std::move(bodies);
|
|
19
|
+
entries_[std::move(key)] = CachedSubtree{std::move(bodies), std::move(warnings)};
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
void ManifoldCache::clear() {
|
|
@@ -13,36 +13,6 @@ namespace oscadeval {
|
|
|
13
13
|
|
|
14
14
|
namespace {
|
|
15
15
|
|
|
16
|
-
std::optional<std::vector<double>> asFlatNumericVector(const ValueList& list) {
|
|
17
|
-
std::vector<double> out;
|
|
18
|
-
out.reserve(list.items.size());
|
|
19
|
-
for (const Value& v : list.items) {
|
|
20
|
-
const double* d = std::get_if<double>(&v);
|
|
21
|
-
if (!d) return std::nullopt;
|
|
22
|
-
out.push_back(*d);
|
|
23
|
-
}
|
|
24
|
-
return out;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// nullopt unless `list` is a non-ragged list of flat-numeric rows.
|
|
28
|
-
std::optional<std::vector<std::vector<double>>> asNumericMatrix(const ValueList& list) {
|
|
29
|
-
std::vector<std::vector<double>> rows;
|
|
30
|
-
rows.reserve(list.items.size());
|
|
31
|
-
for (const Value& rowValue : list.items) {
|
|
32
|
-
const ListPtr* rowList = std::get_if<ListPtr>(&rowValue);
|
|
33
|
-
if (!rowList || !*rowList) return std::nullopt;
|
|
34
|
-
auto row = asFlatNumericVector(**rowList);
|
|
35
|
-
if (!row) return std::nullopt;
|
|
36
|
-
rows.push_back(std::move(*row));
|
|
37
|
-
}
|
|
38
|
-
if (rows.empty()) return rows;
|
|
39
|
-
const size_t width = rows.front().size();
|
|
40
|
-
for (const auto& row : rows) {
|
|
41
|
-
if (row.size() != width) return std::nullopt;
|
|
42
|
-
}
|
|
43
|
-
return rows;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
16
|
Value makeList(std::vector<Value> items) {
|
|
47
17
|
return Value{std::make_shared<const ValueList>(ValueList{std::move(items)})};
|
|
48
18
|
}
|
|
@@ -43,7 +43,10 @@ add_executable(oscad_eval_tests
|
|
|
43
43
|
test_unexpected_args.cpp
|
|
44
44
|
test_cli.cpp
|
|
45
45
|
)
|
|
46
|
-
|
|
46
|
+
# oscad_cli_lib PUBLIC-links openscad_cpp_evaluator, so naming it here too
|
|
47
|
+
# put the archive on the link line twice ("ld: warning: ignoring duplicate
|
|
48
|
+
# libraries").
|
|
49
|
+
target_link_libraries(oscad_eval_tests PRIVATE oscad_cli_lib GTest::gtest_main)
|
|
47
50
|
# stb_image_write.h, used only by this test binary to generate a PNG
|
|
48
51
|
# fixture for ToRenderableBodies/surface() image-loading tests.
|
|
49
52
|
target_include_directories(oscad_eval_tests PRIVATE ${stb_SOURCE_DIR})
|
|
@@ -392,3 +392,52 @@ TEST(HullOpenMesh, ASiblingAfterAHullStillWarns) {
|
|
|
392
392
|
[&](const std::string& m) { if (warning.empty()) warning = m; });
|
|
393
393
|
EXPECT_NE(warning.find("mesh is not closed"), std::string::npos) << warning;
|
|
394
394
|
}
|
|
395
|
+
|
|
396
|
+
// A count alone is actionable on a hand-written face list and useless on
|
|
397
|
+
// generated geometry: three bad edges in a few thousand triangles cannot be
|
|
398
|
+
// found by eye. The message names one of them. Issue #187, from BelfrySCAD
|
|
399
|
+
// #521, where the author searched the render, hunted for magenta backfaces
|
|
400
|
+
// and opened the model in OpenSCAD without ever locating the hole.
|
|
401
|
+
TEST(OpenMeshWarning, NamesACoordinateOfOneBoundaryEdge) {
|
|
402
|
+
std::string warning;
|
|
403
|
+
// The lid is missing, so the four top edges are open. Every one of them
|
|
404
|
+
// has z=10, whichever the map happens to name first.
|
|
405
|
+
evalSrc("polyhedron(points=[[0,0,0],[10,0,0],[10,10,0],[0,10,0],\n"
|
|
406
|
+
" [0,0,10],[10,0,10],[10,10,10],[0,10,10]],\n"
|
|
407
|
+
" faces=[[0,1,2,3],[0,4,5,1],[1,5,6,2],[2,6,7,3],[3,7,4,0]]);\n",
|
|
408
|
+
[&](const std::string& m) { if (warning.empty()) warning = m; });
|
|
409
|
+
|
|
410
|
+
EXPECT_NE(warning.find("4 boundary edge(s)"), std::string::npos) << warning;
|
|
411
|
+
EXPECT_NE(warning.find("first at ["), std::string::npos) << warning;
|
|
412
|
+
EXPECT_NE(warning.find(" - ["), std::string::npos) << warning;
|
|
413
|
+
// Both endpoints of an open edge here lie on the missing lid.
|
|
414
|
+
// Vertices 4..7 are the missing lid's corners, so the open edges are
|
|
415
|
+
// (4,5) (5,6) (6,7) (4,7); std::map names (4,5) first.
|
|
416
|
+
EXPECT_NE(warning.find("first at [0, 0, 10] - [10, 0, 10]"), std::string::npos)
|
|
417
|
+
<< "expected the lowest-indexed open edge, deterministically: " << warning;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// The named edge must not move between runs. An identifier that changes
|
|
421
|
+
// render to render is worse than none -- it sends the author somewhere new
|
|
422
|
+
// each time they look.
|
|
423
|
+
TEST(OpenMeshWarning, TheNamedEdgeIsStableAcrossRuns) {
|
|
424
|
+
const char* src = "polyhedron(points=[[0,0,0],[10,0,0],[10,10,0],[0,10,0],\n"
|
|
425
|
+
" [0,0,10],[10,0,10],[10,10,10],[0,10,10]],\n"
|
|
426
|
+
" faces=[[0,1,2,3],[0,4,5,1],[1,5,6,2],[2,6,7,3],[3,7,4,0]]);\n";
|
|
427
|
+
std::string first, second;
|
|
428
|
+
evalSrc(src, [&](const std::string& m) { if (first.empty()) first = m; });
|
|
429
|
+
evalSrc(src, [&](const std::string& m) { if (second.empty()) second = m; });
|
|
430
|
+
EXPECT_EQ(first, second);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// A closed mesh says nothing at all: the coordinate clause must not appear,
|
|
434
|
+
// and no warning should be raised to carry it.
|
|
435
|
+
TEST(OpenMeshWarning, AClosedMeshStaysSilent) {
|
|
436
|
+
std::string warning;
|
|
437
|
+
evalSrc("polyhedron(points=[[0,0,0],[10,0,0],[10,10,0],[0,10,0],\n"
|
|
438
|
+
" [0,0,10],[10,0,10],[10,10,10],[0,10,10]],\n"
|
|
439
|
+
" faces=[[0,1,2,3],[4,7,6,5],[0,4,5,1],[1,5,6,2],\n"
|
|
440
|
+
" [2,6,7,3],[3,7,4,0]]);\n",
|
|
441
|
+
[&](const std::string& m) { if (warning.empty()) warning = m; });
|
|
442
|
+
EXPECT_EQ(warning, "");
|
|
443
|
+
}
|
{openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/tests/test_manifold_cache.cpp
RENAMED
|
@@ -433,3 +433,66 @@ TEST(ManifoldCache, ClearRemovesEntriesForcingRegeneration) {
|
|
|
433
433
|
Evaluated second = evalSrcWithCache("cube(5);", cache);
|
|
434
434
|
EXPECT_FALSE(second.ev.idToNode.empty()); // no longer a cache hit after clear()
|
|
435
435
|
}
|
|
436
|
+
|
|
437
|
+
// An open polyhedron warns every time it is drawn, not only the first time.
|
|
438
|
+
// A cache hit runs no GenerateFn, so before warnings were stored in the entry
|
|
439
|
+
// the second render of unchanged source went silent and a permanently-broken
|
|
440
|
+
// mesh looked intermittent -- BelfrySCAD issue #521, where the author lost an
|
|
441
|
+
// afternoon to it and could not find the "sometimes" in their own code.
|
|
442
|
+
TEST(ManifoldCache, AHitReplaysTheWarningsGeneratingItRaised) {
|
|
443
|
+
// A cube missing one face: five quads, so the mesh has boundary edges.
|
|
444
|
+
const std::string src = R"(
|
|
445
|
+
polyhedron(
|
|
446
|
+
points=[[-1,-1,-1],[1,-1,-1],[1,1,-1],[-1,1,-1],
|
|
447
|
+
[-1,-1, 1],[1,-1, 1],[1,1, 1],[-1,1, 1]],
|
|
448
|
+
faces=[[0,1,2,3],[4,7,6,5],[0,4,5,1],[1,5,6,2],[2,6,7,3]]);
|
|
449
|
+
)";
|
|
450
|
+
auto cache = std::make_shared<ManifoldCache>();
|
|
451
|
+
auto countWarnings = [&] {
|
|
452
|
+
int n = 0;
|
|
453
|
+
evalSrcWithCache(src, cache, [&](const std::string& line) {
|
|
454
|
+
if (line.find("mesh is not closed") != std::string::npos) ++n;
|
|
455
|
+
});
|
|
456
|
+
return n;
|
|
457
|
+
};
|
|
458
|
+
EXPECT_EQ(countWarnings(), 1) << "cold cache: the generate pass runs and warns";
|
|
459
|
+
EXPECT_EQ(countWarnings(), 1) << "cache hit must replay, not swallow";
|
|
460
|
+
EXPECT_EQ(countWarnings(), 1) << "and keep replaying";
|
|
461
|
+
cache->clear();
|
|
462
|
+
EXPECT_EQ(countWarnings(), 1) << "after clear, generated afresh";
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// The replay must survive a hit ABOVE the node that warned: a parent entry
|
|
466
|
+
// skips its whole subtree, so it has to carry what the subtree said.
|
|
467
|
+
TEST(ManifoldCache, AHitOnAnAncestorStillReplaysADescendantsWarning) {
|
|
468
|
+
const std::string src = R"(
|
|
469
|
+
translate([1,0,0]) polyhedron(
|
|
470
|
+
points=[[-1,-1,-1],[1,-1,-1],[1,1,-1],[-1,1,-1],
|
|
471
|
+
[-1,-1, 1],[1,-1, 1],[1,1, 1],[-1,1, 1]],
|
|
472
|
+
faces=[[0,1,2,3],[4,7,6,5],[0,4,5,1],[1,5,6,2],[2,6,7,3]]);
|
|
473
|
+
)";
|
|
474
|
+
auto cache = std::make_shared<ManifoldCache>();
|
|
475
|
+
auto countWarnings = [&] {
|
|
476
|
+
int n = 0;
|
|
477
|
+
evalSrcWithCache(src, cache, [&](const std::string& line) {
|
|
478
|
+
if (line.find("mesh is not closed") != std::string::npos) ++n;
|
|
479
|
+
});
|
|
480
|
+
return n;
|
|
481
|
+
};
|
|
482
|
+
EXPECT_EQ(countWarnings(), 1);
|
|
483
|
+
EXPECT_EQ(countWarnings(), 1) << "the translate() hit must replay its child's warning";
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// A clean script stays clean: replay must not invent warnings, and a hit on
|
|
487
|
+
// a node that said nothing must say nothing.
|
|
488
|
+
TEST(ManifoldCache, AHitOnAQuietSubtreeStaysQuiet) {
|
|
489
|
+
auto cache = std::make_shared<ManifoldCache>();
|
|
490
|
+
auto countLines = [&] {
|
|
491
|
+
int n = 0;
|
|
492
|
+
evalSrcWithCache("difference() { cube(10, center=true); sphere(6); }", cache,
|
|
493
|
+
[&](const std::string&) { ++n; });
|
|
494
|
+
return n;
|
|
495
|
+
};
|
|
496
|
+
EXPECT_EQ(countLines(), 0);
|
|
497
|
+
EXPECT_EQ(countLines(), 0);
|
|
498
|
+
}
|
|
File without changes
|
{openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.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
|
|
File without changes
|
|
File without changes
|
{openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/examples/eval_perf_benchmark.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.0}/examples/manifold_cache_reuse.cpp
RENAMED
|
File without changes
|
{openscad_cpp_evaluator-1.23.1 → openscad_cpp_evaluator-1.24.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
|