openscad-cpp-evaluator 1.45.3__tar.gz → 1.47.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.45.3 → openscad_cpp_evaluator-1.47.0}/CLAUDE.md +5 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/function_builtins.cpp +3 -4
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/topology.cpp +274 -41
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_booleans.cpp +284 -7
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_feature_detection.cpp +3 -3
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/uv.lock +1 -1
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/README.md +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/cmake/patch_manifold.cmake +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/LICENSE +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/.DS_Store +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_profile_time.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/profile_time.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/import/scene_import.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/xkcd_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/xkcd_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_discretizer.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_openscad_parity.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_profile_time.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_undef_args.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/tools/cli/main.cpp +0 -0
|
@@ -601,6 +601,11 @@ grep for `ponytail:`.
|
|
|
601
601
|
One `LevelSet` pass either way; a bounded range *could* be
|
|
602
602
|
`difference(levelset(hi), levelset(lo))` but that meshes twice and then booleans.
|
|
603
603
|
3D wraps `Manifold::LevelSet` with a C++ sampling lambda; no new Manifold API.
|
|
604
|
+
**`edge` may be a vector**, one spacing per axis (`[ex,ey,ez]`, or `[ex,ey]` in 2D), as BOSL2's
|
|
605
|
+
`isosurface()` takes `voxel_size`. `LevelSet` takes one edge length, so the 3D path meshes the
|
|
606
|
+
field squashed to unit spacing and `Scale`s the result back -- exact, since with tolerance -1 a
|
|
607
|
+
vertex is a linear interpolation along a lattice edge, which commutes with an axis scale. A plain
|
|
608
|
+
number takes the old path unchanged. `supported_feature("levelset")` is **2** from this change.
|
|
604
609
|
**The field is a grid OR a `function(x,y,z)`, and the two trade off against each other** —
|
|
605
610
|
neither is simply better:
|
|
606
611
|
|
{openscad_cpp_evaluator-1.45.3 → openscad_cpp_evaluator-1.47.0}/src/builtins/function_builtins.cpp
RENAMED
|
@@ -976,9 +976,8 @@ namespace {
|
|
|
976
976
|
// is supposed to be safe).
|
|
977
977
|
//
|
|
978
978
|
// A LEVEL rather than a boolean so a feature whose semantics change later
|
|
979
|
-
// can be told apart from its earlier self.
|
|
980
|
-
//
|
|
981
|
-
// observe what a build without supported_feature() did anyway.
|
|
979
|
+
// can be told apart from its earlier self. A script cannot observe what a
|
|
980
|
+
// build without supported_feature() did, so every feature starts at 1.
|
|
982
981
|
//
|
|
983
982
|
// This is the answer to a real hazard: OpenSCAD does not reject arguments or
|
|
984
983
|
// names it doesn't know -- children(separate=true) is silently ignored there
|
|
@@ -988,7 +987,7 @@ const std::unordered_map<std::string, double>& featureLevels() {
|
|
|
988
987
|
static const std::unordered_map<std::string, double> levels = {
|
|
989
988
|
{"render-expr", 1.0}, // render() in expression position
|
|
990
989
|
{"linear-solve", 1.0}, // linear_solve(A, b) -> {x, det, singular}
|
|
991
|
-
{"levelset",
|
|
990
|
+
{"levelset", 2.0}, // levelset(field, bounds, isovalue); 2: edge may be a vector
|
|
992
991
|
{"polyhedron-vnf", 1.0}, // polyhedron(vnf) / polyhedron(object)
|
|
993
992
|
{"separate-children", 1.0}, // children(..., separate=true)
|
|
994
993
|
{"minkowski-diff", 1.0}, // minkowski_difference()
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
#include <manifold/polygon.h>
|
|
8
8
|
|
|
9
|
+
#include <algorithm>
|
|
10
|
+
|
|
9
11
|
namespace oscadeval {
|
|
10
12
|
|
|
11
13
|
// simplify()'s default tolerance, as a fraction of the body's bounding-box
|
|
@@ -663,14 +665,30 @@ std::vector<ColoredBody> generateMeshRepair(Evaluator& ev, const CSGParams& para
|
|
|
663
665
|
// The trade is memory: ~67 bytes per cell, so 200^3 is about 550 MB and that
|
|
664
666
|
// is the practical ceiling. A callback samples lazily and has no ceiling.
|
|
665
667
|
//
|
|
666
|
-
// Accuracy is bounded by the GRID, not by Manifold.
|
|
667
|
-
//
|
|
668
|
-
//
|
|
669
|
-
//
|
|
670
|
-
//
|
|
668
|
+
// Accuracy is bounded by the GRID, not by Manifold. At the grid's own
|
|
669
|
+
// spacing (the default) the grid is marched directly, as BOSL2's
|
|
670
|
+
// isosurface() does -- see marchingCubes(). An edge= asking for a different
|
|
671
|
+
// spacing resamples it through LevelSet instead, which samples a
|
|
672
|
+
// body-centred cubic lattice (sdf.cpp:440-446) that a plain cubic grid does
|
|
673
|
+
// not line up with, so the lambda interpolates trilinearly between samples.
|
|
671
674
|
|
|
672
675
|
namespace {
|
|
673
676
|
|
|
677
|
+
// A sample as the field arrays and field functions hand it over. +-INF is a
|
|
678
|
+
// legal sample -- a metaball field is 1/0 wherever a grid point lands on a
|
|
679
|
+
// centre (#744 on BelfrySCAD) -- but it cannot be used as is: the trilinear
|
|
680
|
+
// sampler weights corners, and 0 * INF is NaN. So it becomes a huge FINITE
|
|
681
|
+
// value, which is the limit BOSL2's isosurface() takes (an edge to an INF
|
|
682
|
+
// corner crosses at the other end). A quarter of DBL_MAX so that sums of
|
|
683
|
+
// weighted corners and bandDistance's subtraction cannot overflow. NaN, or
|
|
684
|
+
// anything not a number, has no meaning and is nullopt.
|
|
685
|
+
std::optional<double> fieldSample(const Value& item) {
|
|
686
|
+
const double* d = std::get_if<double>(&item);
|
|
687
|
+
if (!d || std::isnan(*d)) return std::nullopt;
|
|
688
|
+
constexpr double kHuge = std::numeric_limits<double>::max() / 4;
|
|
689
|
+
return std::clamp(*d, -kHuge, kHuge);
|
|
690
|
+
}
|
|
691
|
+
|
|
674
692
|
struct ScalarField {
|
|
675
693
|
std::vector<double> v; // flat, x fastest
|
|
676
694
|
size_t nx = 0, ny = 0, nz = 0;
|
|
@@ -698,8 +716,8 @@ std::optional<ScalarField> readField(const Value& val) {
|
|
|
698
716
|
return std::nullopt;
|
|
699
717
|
}
|
|
700
718
|
for (size_t k = 0; k < f.nz; ++k) {
|
|
701
|
-
const double
|
|
702
|
-
if (!d
|
|
719
|
+
const std::optional<double> d = fieldSample((*zs)->items[k]);
|
|
720
|
+
if (!d) return std::nullopt;
|
|
703
721
|
f.v[(k * f.ny + j) * f.nx + i] = *d;
|
|
704
722
|
}
|
|
705
723
|
}
|
|
@@ -722,8 +740,8 @@ std::optional<std::vector<std::vector<double>>> readPlane(const Value& val) {
|
|
|
722
740
|
std::vector<double> row;
|
|
723
741
|
row.reserve(ny);
|
|
724
742
|
for (const Value& item : (*ys)->items) {
|
|
725
|
-
const double
|
|
726
|
-
if (!d
|
|
743
|
+
const std::optional<double> d = fieldSample(item);
|
|
744
|
+
if (!d) return std::nullopt;
|
|
727
745
|
row.push_back(*d);
|
|
728
746
|
}
|
|
729
747
|
out.push_back(std::move(row));
|
|
@@ -890,6 +908,162 @@ manifold::Polygons marchingSquares(const Contours2d& g) {
|
|
|
890
908
|
}
|
|
891
909
|
|
|
892
910
|
|
|
911
|
+
// -- 3D: marching cubes on the grid itself -----------------------------------
|
|
912
|
+
//
|
|
913
|
+
// For a grid sampled at the spacing it was given, Manifold's LevelSet is the
|
|
914
|
+
// wrong tool: it samples its own body-centred lattice, which does not line up
|
|
915
|
+
// with the grid, so it meshes a trilinear blend of the data rather than the
|
|
916
|
+
// data. Measured on #745 on BelfrySCAD, that left a metaball field visibly
|
|
917
|
+
// more faceted than BOSL2's isosurface(), which marches the grid itself. So
|
|
918
|
+
// this does too.
|
|
919
|
+
//
|
|
920
|
+
// No 256-case table. The table's hard part is the ambiguous face (two
|
|
921
|
+
// inside corners on a diagonal), and a table that resolves it per CELL can
|
|
922
|
+
// disagree with the neighbouring cell and leave a crack -- fatal here, since
|
|
923
|
+
// Manifold needs a closed mesh. So the triangles are built per FACE instead:
|
|
924
|
+
// each face's crossings are paired into segments by a rule that reads only
|
|
925
|
+
// that face's four values (the face-centre average decides a saddle, as the
|
|
926
|
+
// 2D path does), so the two cells sharing a face always agree. A cell's
|
|
927
|
+
// segments then link into closed loops, one polygon each. Vertices are keyed
|
|
928
|
+
// on GRID EDGE identity, so neighbours share them by construction, exactly as
|
|
929
|
+
// marchingSquares keys on edges rather than coordinates.
|
|
930
|
+
//
|
|
931
|
+
// Orientation: walking a face's corners anticlockwise as seen from outside
|
|
932
|
+
// the cell, a segment runs from an outside->inside crossing to an
|
|
933
|
+
// inside->outside one. A loop of such segments, read in order, is a polygon
|
|
934
|
+
// whose normal points from inside to outside -- Manifold's convention, with
|
|
935
|
+
// inside the positive side.
|
|
936
|
+
//
|
|
937
|
+
// The field arrives as band distance (positive inside) with a ring of
|
|
938
|
+
// "outside" round it, like the 2D path, so every surface closes; the caller
|
|
939
|
+
// clips the overhang back to the bounds.
|
|
940
|
+
manifold::MeshGL64 marchingCubes(const std::vector<double>& d, const size_t n[3],
|
|
941
|
+
const std::array<double, 3>& org, const std::array<double, 3>& h) {
|
|
942
|
+
const auto P = [&](size_t i, size_t j, size_t k) { return (k * n[1] + j) * n[0] + i; };
|
|
943
|
+
// corner c of a cell is offset (c&1, c>>1&1, c>>2&1). Each face's
|
|
944
|
+
// corners, anticlockwise as seen from outside.
|
|
945
|
+
static constexpr int kFaces[6][4] = {
|
|
946
|
+
{0, 2, 3, 1}, {4, 5, 7, 6}, // -z, +z
|
|
947
|
+
{0, 4, 6, 2}, {1, 3, 7, 5}, // -x, +x
|
|
948
|
+
{0, 1, 5, 4}, {2, 6, 7, 3}, // -y, +y
|
|
949
|
+
};
|
|
950
|
+
manifold::MeshGL64 mesh;
|
|
951
|
+
mesh.numProp = 3;
|
|
952
|
+
// ponytail: one int per grid edge, ~12 bytes a sample next to the
|
|
953
|
+
// field's own ~67; key the vertices per slab if this ever binds.
|
|
954
|
+
std::vector<int64_t> edgeVert(3 * n[0] * n[1] * n[2], -1);
|
|
955
|
+
const auto addVert = [&](double x, double y, double z) {
|
|
956
|
+
mesh.vertProperties.insert(mesh.vertProperties.end(), {x, y, z});
|
|
957
|
+
return static_cast<int64_t>(mesh.vertProperties.size() / 3 - 1);
|
|
958
|
+
};
|
|
959
|
+
for (size_t k = 0; k + 1 < n[2]; ++k) {
|
|
960
|
+
for (size_t j = 0; j + 1 < n[1]; ++j) {
|
|
961
|
+
for (size_t i = 0; i + 1 < n[0]; ++i) {
|
|
962
|
+
double v[8];
|
|
963
|
+
size_t p[8];
|
|
964
|
+
int inside = 0;
|
|
965
|
+
for (int c = 0; c < 8; ++c) {
|
|
966
|
+
p[c] = P(i + (c & 1), j + (c >> 1 & 1), k + (c >> 2 & 1));
|
|
967
|
+
v[c] = d[p[c]];
|
|
968
|
+
inside += v[c] > 0.0;
|
|
969
|
+
}
|
|
970
|
+
if (inside == 0 || inside == 8) continue;
|
|
971
|
+
// The vertex on the edge between corners a and b.
|
|
972
|
+
const auto vert = [&](int a, int b) -> int64_t {
|
|
973
|
+
if (a > b) std::swap(a, b); // a is the lower end
|
|
974
|
+
const int axis = (b - a) == 1 ? 0 : (b - a) == 2 ? 1 : 2;
|
|
975
|
+
int64_t& id = edgeVert[3 * p[a] + static_cast<size_t>(axis)];
|
|
976
|
+
if (id < 0) {
|
|
977
|
+
const double t = v[a] / (v[a] - v[b]);
|
|
978
|
+
const double x = org[0] + h[0] * (static_cast<double>(i + (a & 1)) + (axis == 0 ? t : 0.0));
|
|
979
|
+
const double y = org[1] + h[1] * (static_cast<double>(j + (a >> 1 & 1)) + (axis == 1 ? t : 0.0));
|
|
980
|
+
const double z = org[2] + h[2] * (static_cast<double>(k + (a >> 2 & 1)) + (axis == 2 ? t : 0.0));
|
|
981
|
+
id = addVert(x, y, z);
|
|
982
|
+
}
|
|
983
|
+
return id;
|
|
984
|
+
};
|
|
985
|
+
// Segments start->end, at most two per face.
|
|
986
|
+
int64_t segFrom[12], segTo[12];
|
|
987
|
+
int nSeg = 0;
|
|
988
|
+
for (const auto& f : kFaces) {
|
|
989
|
+
int64_t cross[4];
|
|
990
|
+
bool outIn[4];
|
|
991
|
+
int nc = 0;
|
|
992
|
+
for (int m = 0; m < 4; ++m) {
|
|
993
|
+
const int a = f[m], b = f[(m + 1) % 4];
|
|
994
|
+
if ((v[a] > 0.0) != (v[b] > 0.0)) {
|
|
995
|
+
cross[nc] = vert(a, b);
|
|
996
|
+
outIn[nc++] = v[b] > 0.0;
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
if (nc == 0) continue;
|
|
1000
|
+
// A saddle joins its inside corners when the face centre
|
|
1001
|
+
// is inside: each out->in crossing then pairs with the
|
|
1002
|
+
// PREVIOUS crossing instead of the next.
|
|
1003
|
+
const bool joined =
|
|
1004
|
+
nc == 4 && v[f[0]] + v[f[1]] + v[f[2]] + v[f[3]] > 0.0;
|
|
1005
|
+
for (int m = 0; m < nc; ++m) {
|
|
1006
|
+
if (!outIn[m]) continue;
|
|
1007
|
+
segFrom[nSeg] = cross[m];
|
|
1008
|
+
segTo[nSeg++] = cross[(m + (joined ? nc - 1 : 1)) % nc];
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
// Link into loops; each vertex starts exactly one segment.
|
|
1012
|
+
bool used[12] = {};
|
|
1013
|
+
for (int s0 = 0; s0 < nSeg; ++s0) {
|
|
1014
|
+
if (used[s0]) continue;
|
|
1015
|
+
int64_t loop[12];
|
|
1016
|
+
int len = 0;
|
|
1017
|
+
for (int s = s0; s >= 0 && !used[s];) {
|
|
1018
|
+
used[s] = true;
|
|
1019
|
+
loop[len++] = segFrom[s];
|
|
1020
|
+
const int64_t want = segTo[s];
|
|
1021
|
+
s = -1;
|
|
1022
|
+
for (int q = 0; q < nSeg; ++q)
|
|
1023
|
+
if (!used[q] && segFrom[q] == want) { s = q; break; }
|
|
1024
|
+
}
|
|
1025
|
+
const auto tri = [&](int64_t a, int64_t b, int64_t c) {
|
|
1026
|
+
mesh.triVerts.insert(mesh.triVerts.end(), {static_cast<uint64_t>(a), static_cast<uint64_t>(b),
|
|
1027
|
+
static_cast<uint64_t>(c)});
|
|
1028
|
+
};
|
|
1029
|
+
const auto at = [&](int64_t id, int axis) {
|
|
1030
|
+
return mesh.vertProperties[static_cast<size_t>(id) * 3 + static_cast<size_t>(axis)];
|
|
1031
|
+
};
|
|
1032
|
+
const auto dist2 = [&](int64_t a, int64_t b) {
|
|
1033
|
+
double s2 = 0;
|
|
1034
|
+
for (int ax = 0; ax < 3; ++ax) s2 += (at(a, ax) - at(b, ax)) * (at(a, ax) - at(b, ax));
|
|
1035
|
+
return s2;
|
|
1036
|
+
};
|
|
1037
|
+
if (len == 3) {
|
|
1038
|
+
tri(loop[0], loop[1], loop[2]);
|
|
1039
|
+
} else if (len == 4) {
|
|
1040
|
+
// Split along the shorter diagonal.
|
|
1041
|
+
if (dist2(loop[0], loop[2]) <= dist2(loop[1], loop[3])) {
|
|
1042
|
+
tri(loop[0], loop[1], loop[2]);
|
|
1043
|
+
tri(loop[0], loop[2], loop[3]);
|
|
1044
|
+
} else {
|
|
1045
|
+
tri(loop[1], loop[2], loop[3]);
|
|
1046
|
+
tri(loop[1], loop[3], loop[0]);
|
|
1047
|
+
}
|
|
1048
|
+
} else if (len > 4) {
|
|
1049
|
+
// A fan from one corner of a 5-7 sided, non-planar
|
|
1050
|
+
// loop can fold; a fan from its centroid cannot.
|
|
1051
|
+
double cx = 0, cy = 0, cz = 0;
|
|
1052
|
+
for (int m = 0; m < len; ++m) {
|
|
1053
|
+
cx += at(loop[m], 0);
|
|
1054
|
+
cy += at(loop[m], 1);
|
|
1055
|
+
cz += at(loop[m], 2);
|
|
1056
|
+
}
|
|
1057
|
+
const int64_t c = addVert(cx / len, cy / len, cz / len);
|
|
1058
|
+
for (int m = 0; m < len; ++m) tri(loop[m], loop[(m + 1) % len], c);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
return mesh;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
893
1067
|
CSGParams resolveLevelSet(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
|
|
894
1068
|
auto [args, effCtx] = resolveCallArgs(ev, node.arguments, ctx);
|
|
895
1069
|
CSGParams params;
|
|
@@ -991,11 +1165,31 @@ std::vector<ColoredBody> generateLevelSet(Evaluator& ev, const CSGParams& params
|
|
|
991
1165
|
const std::array<double, 3> origin = *lo;
|
|
992
1166
|
std::array<double, 3> spacing{1.0, 1.0, 1.0};
|
|
993
1167
|
double edge = 0.0;
|
|
1168
|
+
// edge may also be one spacing per axis, as BOSL2's isosurface() takes
|
|
1169
|
+
// voxel_size -- a thin plate wants fine sampling across it and coarse
|
|
1170
|
+
// along it (#729 on BelfrySCAD). edgeV is then the vector and `edge`
|
|
1171
|
+
// its smallest component; for a plain number edgeV is unused.
|
|
1172
|
+
std::array<double, 3> edgeV{0.0, 0.0, 0.0};
|
|
1173
|
+
bool edgeVec = false;
|
|
994
1174
|
// Grid spacing is filled in below, once the array has been read at the
|
|
995
1175
|
// right dimensionality. Finer than the grid buys nothing.
|
|
996
|
-
|
|
1176
|
+
const Value& edgeArg = params.at("edge");
|
|
1177
|
+
if (const double* e = std::get_if<double>(&edgeArg)) {
|
|
997
1178
|
if (*e > 0.0) edge = *e;
|
|
998
1179
|
else ev.warn("levelset(): edge must be positive", &node.position());
|
|
1180
|
+
} else if (!std::holds_alternative<std::monostate>(edgeArg)) {
|
|
1181
|
+
const std::optional<std::vector<double>> ev3 = numbersOrInf(edgeArg);
|
|
1182
|
+
bool ok = ev3 && ev3->size() == bLo->size();
|
|
1183
|
+
for (size_t a = 0; ok && a < ev3->size(); ++a) ok = std::isfinite((*ev3)[a]) && (*ev3)[a] > 0.0;
|
|
1184
|
+
if (ok) {
|
|
1185
|
+
edgeVec = true;
|
|
1186
|
+
for (size_t a = 0; a < ev3->size(); ++a) edgeV[a] = (*ev3)[a];
|
|
1187
|
+
edge = *std::min_element(ev3->begin(), ev3->end());
|
|
1188
|
+
} else {
|
|
1189
|
+
ev.warn(is2d ? "levelset(): edge must be a positive number or [ex, ey]"
|
|
1190
|
+
: "levelset(): edge must be a positive number or [ex, ey, ez]",
|
|
1191
|
+
&node.position());
|
|
1192
|
+
}
|
|
999
1193
|
}
|
|
1000
1194
|
if (edge <= 0.0 && fieldFn) {
|
|
1001
1195
|
// No grid to infer it from. Guessing would silently pick either a
|
|
@@ -1060,8 +1254,9 @@ std::vector<ColoredBody> generateLevelSet(Evaluator& ev, const CSGParams& params
|
|
|
1060
1254
|
return out;
|
|
1061
1255
|
}
|
|
1062
1256
|
// function(x,y): edge= gives the spacing, as in 3D
|
|
1063
|
-
|
|
1064
|
-
|
|
1257
|
+
const double ex = edgeVec ? edgeV[0] : edge, ey = edgeVec ? edgeV[1] : edge;
|
|
1258
|
+
nx = static_cast<size_t>(std::floor(((*bHi)[0] - (*bLo)[0]) / ex)) + 1;
|
|
1259
|
+
ny = static_cast<size_t>(std::floor(((*bHi)[1] - (*bLo)[1]) / ey)) + 1;
|
|
1065
1260
|
if (nx < 2 || ny < 2) {
|
|
1066
1261
|
ev.warn("levelset(): edge is larger than the bounds", &node.position());
|
|
1067
1262
|
return {};
|
|
@@ -1083,8 +1278,7 @@ std::vector<ColoredBody> generateLevelSet(Evaluator& ev, const CSGParams& params
|
|
|
1083
1278
|
bound.set(fnParams2[1], Value{(*bLo)[1] + static_cast<double>(j) * sy});
|
|
1084
1279
|
const Value outv =
|
|
1085
1280
|
ev.evalFunctionLiteralFromBound(**fieldFn, std::move(bound), *fnCtx, &node.position());
|
|
1086
|
-
const double
|
|
1087
|
-
const double val = (d && std::isfinite(*d)) ? *d : std::numeric_limits<double>::max();
|
|
1281
|
+
const double val = fieldSample(outv).value_or(std::numeric_limits<double>::max());
|
|
1088
1282
|
g.v[(j + 1) * g.nx + (i + 1)] = bandDistance(val, isoLo, isoHi, invert);
|
|
1089
1283
|
}
|
|
1090
1284
|
}
|
|
@@ -1100,6 +1294,7 @@ std::vector<ColoredBody> generateLevelSet(Evaluator& ev, const CSGParams& params
|
|
|
1100
1294
|
}
|
|
1101
1295
|
|
|
1102
1296
|
|
|
1297
|
+
bool marchGrid = false;
|
|
1103
1298
|
if (!fieldFn) {
|
|
1104
1299
|
field = readField(fieldArg);
|
|
1105
1300
|
if (!field) {
|
|
@@ -1114,7 +1309,18 @@ std::vector<ColoredBody> generateLevelSet(Evaluator& ev, const CSGParams& params
|
|
|
1114
1309
|
spacing = {((*bHi)[0] - (*bLo)[0]) / static_cast<double>(field->nx - 1),
|
|
1115
1310
|
((*bHi)[1] - (*bLo)[1]) / static_cast<double>(field->ny - 1),
|
|
1116
1311
|
((*bHi)[2] - (*bLo)[2]) / static_cast<double>(field->nz - 1)};
|
|
1117
|
-
|
|
1312
|
+
// Marched on the grid itself unless edge= asks for a different
|
|
1313
|
+
// spacing. A 1e-9 relative slack so an edge typed as the spacing,
|
|
1314
|
+
// or computed from the same bounds, still counts as it.
|
|
1315
|
+
const auto same = [](double a, double b) { return std::abs(a - b) <= 1e-9 * std::max(a, b); };
|
|
1316
|
+
marchGrid = edge <= 0.0;
|
|
1317
|
+
if (!marchGrid) {
|
|
1318
|
+
marchGrid = true;
|
|
1319
|
+
for (int a = 0; a < 3; ++a) marchGrid = marchGrid && same(edgeVec ? edgeV[a] : edge, spacing[a]);
|
|
1320
|
+
}
|
|
1321
|
+
// Also when edge= was given but unusable (warned above): edge 0
|
|
1322
|
+
// would ask Manifold for an infinitely fine lattice.
|
|
1323
|
+
if (edge <= 0.0) edge = std::min({spacing[0], spacing[1], spacing[2]});
|
|
1118
1324
|
}
|
|
1119
1325
|
|
|
1120
1326
|
if (fieldFn && fnParams2.size() < 3) {
|
|
@@ -1128,10 +1334,9 @@ std::vector<ColoredBody> generateLevelSet(Evaluator& ev, const CSGParams& params
|
|
|
1128
1334
|
const double xyz[3] = {p.x, p.y, p.z};
|
|
1129
1335
|
for (int a = 0; a < 3; ++a) bound.set(fnParams2[static_cast<size_t>(a)], Value{xyz[a]});
|
|
1130
1336
|
const Value out = ev.evalFunctionLiteralFromBound(**fieldFn, std::move(bound), *fnCtx, &node.position());
|
|
1131
|
-
const double* d = std::get_if<double>(&out);
|
|
1132
1337
|
// A field that returns junk at one point must not abort the whole
|
|
1133
|
-
// build;
|
|
1134
|
-
const double v = (
|
|
1338
|
+
// build; it becomes a huge value instead. +-INF keeps its sign.
|
|
1339
|
+
const double v = fieldSample(out).value_or(std::numeric_limits<double>::max());
|
|
1135
1340
|
return bandDistance(v, isoLo, isoHi, invert);
|
|
1136
1341
|
};
|
|
1137
1342
|
|
|
@@ -1155,18 +1360,13 @@ std::vector<ColoredBody> generateLevelSet(Evaluator& ev, const CSGParams& params
|
|
|
1155
1360
|
if (i0[a] > n[a] - 2) i0[a] = n[a] - 2;
|
|
1156
1361
|
t[a] = g[a] - static_cast<double>(i0[a]);
|
|
1157
1362
|
}
|
|
1158
|
-
// Outside the sampled block the
|
|
1159
|
-
//
|
|
1160
|
-
//
|
|
1161
|
-
//
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
const double raw = (pos[a] - origin[a]) / spacing[a];
|
|
1166
|
-
if (raw < 0.0) outside = std::max(outside, -raw);
|
|
1167
|
-
else if (raw > maxg) outside = std::max(outside, raw - maxg);
|
|
1168
|
-
}
|
|
1169
|
-
if (outside > 0.0) return invert ? (1.0 + outside) : -(1.0 + outside);
|
|
1363
|
+
// Outside the sampled block the clamping above extends the boundary
|
|
1364
|
+
// values outward, so a surface meeting the box runs straight on into
|
|
1365
|
+
// the padding and the clip to `bounds` below leaves a clean plane.
|
|
1366
|
+
// Answering "outside" there instead (as this once did) made Manifold
|
|
1367
|
+
// close the surface right AT the box face, along its own lattice: a
|
|
1368
|
+
// waffle-textured staircase INSIDE the bounds, which the clip could
|
|
1369
|
+
// not remove (#745 on BelfrySCAD).
|
|
1170
1370
|
|
|
1171
1371
|
double acc = 0.0;
|
|
1172
1372
|
for (int c = 0; c < 8; ++c) {
|
|
@@ -1187,21 +1387,54 @@ std::vector<ColoredBody> generateLevelSet(Evaluator& ev, const CSGParams& params
|
|
|
1187
1387
|
//
|
|
1188
1388
|
// Exactly the fix already applied to the 2D path (clipToBounds); it was
|
|
1189
1389
|
// not applied here at the time because the 2D error was the one measured.
|
|
1190
|
-
const
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
//
|
|
1195
|
-
//
|
|
1196
|
-
//
|
|
1197
|
-
//
|
|
1390
|
+
const manifold::vec3 E = edgeVec ? manifold::vec3(edgeV[0], edgeV[1], edgeV[2]) : manifold::vec3(edge);
|
|
1391
|
+
const manifold::vec3 pad = 2.0 * E;
|
|
1392
|
+
manifold::Box bounds(manifold::vec3(origin[0], origin[1], origin[2]) - pad,
|
|
1393
|
+
manifold::vec3((*hi)[0], (*hi)[1], (*hi)[2]) + pad);
|
|
1394
|
+
// tolerance: Manifold root-finds along each crossing lattice edge until
|
|
1395
|
+
// the bracket is within it (a distance along the edge, so independent of
|
|
1396
|
+
// the field's units), instead of interpolating linearly between the two
|
|
1397
|
+
// lattice samples. 1% of the edge. Measured on #745 on BelfrySCAD: the
|
|
1398
|
+
// function form's vertices go from up to 0.2 off the true surface to on
|
|
1399
|
+
// it, and the mean face-normal error on a per-axis edge halves to
|
|
1400
|
+
// BOSL2's own; a grid gains too, since the trilinear field between
|
|
1401
|
+
// samples is not linear along a lattice edge. Costs 11-20% more work.
|
|
1402
|
+
//
|
|
1198
1403
|
// canParallel is the crux: safe for a grid because the lambda is pure
|
|
1199
1404
|
// C++, and NOT safe for a function, which re-enters the evaluator.
|
|
1200
1405
|
// Manifold: parallel policies "will crash language runtimes with runtime
|
|
1201
1406
|
// locks that expect to not be called back by unregistered threads".
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1407
|
+
//
|
|
1408
|
+
// LevelSet takes a single edge length, so a per-axis edge meshes a field
|
|
1409
|
+
// squashed to unit spacing on every axis and stretches the result back.
|
|
1410
|
+
// The tolerance there is 1% of the unit edge, so 1% of each axis's own.
|
|
1411
|
+
const double tol = 0.01 * (edgeVec ? 1.0 : edge);
|
|
1412
|
+
manifold::Manifold solid;
|
|
1413
|
+
if (marchGrid) {
|
|
1414
|
+
const size_t n[3] = {field->nx + 2, field->ny + 2, field->nz + 2};
|
|
1415
|
+
std::vector<double> d(n[0] * n[1] * n[2], -1.0); // the "outside" ring
|
|
1416
|
+
for (size_t k = 0; k < field->nz; ++k)
|
|
1417
|
+
for (size_t j = 0; j < field->ny; ++j)
|
|
1418
|
+
for (size_t i = 0; i < field->nx; ++i)
|
|
1419
|
+
d[((k + 1) * n[1] + (j + 1)) * n[0] + (i + 1)] =
|
|
1420
|
+
bandDistance(field->at(i, j, k), isoLo, isoHi, invert);
|
|
1421
|
+
const std::array<double, 3> org{origin[0] - spacing[0], origin[1] - spacing[1], origin[2] - spacing[2]};
|
|
1422
|
+
solid = manifold::Manifold(marchingCubes(d, n, org, spacing));
|
|
1423
|
+
// Never expected; but a mesh Manifold refuses must not cost the
|
|
1424
|
+
// user their shape, so fall back to resampling it.
|
|
1425
|
+
if (solid.Status() != manifold::Manifold::Error::NoError) marchGrid = false;
|
|
1426
|
+
}
|
|
1427
|
+
if (!marchGrid && !edgeVec) {
|
|
1428
|
+
solid = fieldFn ? manifold::Manifold::LevelSet(sampleFn, bounds, edge, 0.0, tol, /*canParallel=*/false)
|
|
1429
|
+
: manifold::Manifold::LevelSet(sampleGrid, bounds, edge, 0.0, tol, /*canParallel=*/true);
|
|
1430
|
+
} else if (!marchGrid) {
|
|
1431
|
+
const manifold::Box unit(bounds.min / E, bounds.max / E);
|
|
1432
|
+
solid = fieldFn ? manifold::Manifold::LevelSet([&](manifold::vec3 q) { return sampleFn(q * E); },
|
|
1433
|
+
unit, 1.0, 0.0, tol, /*canParallel=*/false)
|
|
1434
|
+
: manifold::Manifold::LevelSet([&](manifold::vec3 q) { return sampleGrid(q * E); },
|
|
1435
|
+
unit, 1.0, 0.0, tol, /*canParallel=*/true);
|
|
1436
|
+
solid = solid.Scale(E);
|
|
1437
|
+
}
|
|
1205
1438
|
|
|
1206
1439
|
if (solid.IsEmpty()) return {};
|
|
1207
1440
|
solid = solid ^ manifold::Manifold::Cube(
|