openscad-cpp-evaluator 0.31.2__tar.gz → 0.32.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/CLAUDE.md +87 -52
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/CMakeLists.txt +58 -5
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/evaluator.hpp +1 -1
- openscad_cpp_evaluator-0.32.2/include/openscad_cpp_evaluator/font_match.hpp +62 -0
- openscad_cpp_evaluator-0.32.2/include/openscad_cpp_evaluator/font_provider.hpp +98 -0
- openscad_cpp_evaluator-0.32.2/include/openscad_cpp_evaluator/freetype_font_provider.hpp +38 -0
- openscad_cpp_evaluator-0.32.2/include/openscad_cpp_evaluator/text_metrics.hpp +40 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/CMakeLists.txt +3 -2
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/function_builtins.cpp +36 -8
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/text.cpp +31 -17
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/expr_eval.cpp +2 -2
- openscad_cpp_evaluator-0.32.2/src/text/font_match.cpp +190 -0
- openscad_cpp_evaluator-0.32.2/src/text/freetype_font_provider.cpp +310 -0
- openscad_cpp_evaluator-0.32.2/src/text/text_metrics.cpp +70 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_bytecode_compiler.cpp +29 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_control_flow.cpp +56 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_function_builtins.cpp +28 -1
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_text.cpp +119 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/uv.lock +1 -1
- openscad_cpp_evaluator-0.31.2/include/openscad_cpp_evaluator/font_provider.hpp +0 -73
- openscad_cpp_evaluator-0.31.2/include/openscad_cpp_evaluator/stb_font_provider.hpp +0 -31
- openscad_cpp_evaluator-0.31.2/include/openscad_cpp_evaluator/text_metrics.hpp +0 -36
- openscad_cpp_evaluator-0.31.2/src/text/stb_font_provider.cpp +0 -171
- openscad_cpp_evaluator-0.31.2/src/text/text_metrics.cpp +0 -87
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/.gitignore +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/.gitmodules +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/LICENSE +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/README.md +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/bindings/module.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/export.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/python/openscad_cpp_evaluator/__init__.py +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/export.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_export.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_python_bindings.py +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/tools/cli/main.cpp +0 -0
|
@@ -12,14 +12,26 @@ OpenSCAD AST and produces Manifold CSG geometry. This port builds on two depende
|
|
|
12
12
|
tag, not vendored) — wired in as of Phase 2
|
|
13
13
|
- Boost.Polygon (`boostorg/polygon` + `boostorg/config`, fetched individually — not the full Boost
|
|
14
14
|
superproject) for `roof()`'s Voronoi-diagram construction — wired in as of Phase 6, see below
|
|
15
|
-
- `nothings/stb` (`stb_image.h
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
- `nothings/stb` (`stb_image.h`; header-only, no build step) for `surface()`'s PNG loader — wired
|
|
16
|
+
in as of Phase 7
|
|
17
|
+
- FreeType (`VER-2-14-3`) and HarfBuzz (`14.3.1`), both via `FetchContent` — the font backend:
|
|
18
|
+
HarfBuzz shapes, FreeType supplies outlines and face metrics. Deliberately NOT fontconfig, the
|
|
19
|
+
third leg of real OpenSCAD's font stack: it is meson-only (no CMake build at all), needs expat,
|
|
20
|
+
and wants a runtime `fonts.conf` plus a cache directory, none of which survives contact with six
|
|
21
|
+
cibuildwheel targets. `src/text/font_match.cpp` reimplements the part of it that `font=` actually
|
|
22
|
+
uses — spec syntax and directory scanning — so name matching behaves identically everywhere
|
|
23
|
+
rather than only where a fontconfig build exists. The two libraries are also kept independent of
|
|
24
|
+
*each other* (`HB_HAVE_FREETYPE=OFF`): HarfBuzz reads the font through its own hb-ot tables
|
|
25
|
+
reader, so no `find_package(Freetype)` has to resolve against a FetchContent target that is
|
|
26
|
+
installed nowhere. Both address glyphs by the same font-internal index and both work in font
|
|
27
|
+
units (`hb_font_set_scale` to unitsPerEm on one side, `FT_LOAD_NO_SCALE` on the other), so the
|
|
28
|
+
split costs nothing to bridge.
|
|
18
29
|
|
|
19
30
|
The full design and phase-by-phase build order live in the plan this repo is being built from:
|
|
20
31
|
`/Users/gminette/.claude/plans/please-plan-out-a-twinkly-anchor.md`. Read it before starting a new
|
|
21
32
|
phase — it has the rationale for every non-obvious choice (value model, `EvalContext` lifetime,
|
|
22
|
-
the `FontProvider`
|
|
33
|
+
the `FontProvider` abstraction (whose built-in backend has since become
|
|
34
|
+
FreeType/HarfBuzz rather than the stb_truetype single-font default the plan describes), why Manifold's
|
|
23
35
|
own vendored `linalg.h` types and not GLM/Eigen, etc.) and the exit criterion each phase needs to
|
|
24
36
|
hit before the next one starts. §6a was corrected during Phase 2 after checking Manifold's real
|
|
25
37
|
source (it no longer uses GLM) — a live example of why the plan says to verify API assumptions
|
|
@@ -43,7 +55,7 @@ CSG-tree shape like union/difference/intersection, role-split via the shared `sp
|
|
|
43
55
|
`POLYLINE`) and SVG (`path`/`polygon`/`polyline`/`rect`/`circle`/`ellipse`, nested
|
|
44
56
|
`transform=`, all path commands including elliptical arcs) 2D contour import in both module
|
|
45
57
|
(Region geometry) and expression (Region value) contexts, and the `FontProvider` abstraction
|
|
46
|
-
(`font_provider.hpp`) + built-in
|
|
58
|
+
(`font_provider.hpp`) + built-in FreeType/HarfBuzz backend + `text()`/`textmetrics()`/
|
|
47
59
|
`fontmetrics()`; and (Phase 8) `ManifoldCache` — an opt-in, thread-safe content-hash cache of
|
|
48
60
|
already-generated CSGNode subtrees (`manifold_cache.hpp`/`.cpp`), plus `rands()`-taint tracking
|
|
49
61
|
(`Evaluator::noteRandsCall()`/`CSGNode::uncacheable`) so a subtree whose resolved content isn't a
|
|
@@ -215,31 +227,45 @@ top-level 2D primitive/projection() script had been silently unexportable via th
|
|
|
215
227
|
Fixed by porting `toRenderableBodies()` (`colored_body.hpp`/`.cpp`) and calling it from the CLI right
|
|
216
228
|
before export, matching the reference's own call site exactly.
|
|
217
229
|
|
|
218
|
-
**Font support
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
`
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
230
|
+
**Font support**: a `FontProvider` abstract interface (`font_provider.hpp`: `resolveFont`/
|
|
231
|
+
`metrics`/`shapeText`/`glyphInkBounds`/`glyphOutline`) with `FreetypeFontProvider` as the built-in
|
|
232
|
+
implementation everything here actually uses. `Evaluator`'s constructor takes an optional
|
|
233
|
+
`shared_ptr<FontProvider>`; if unset, `Evaluator::fontProvider()` constructs the built-in one
|
|
234
|
+
lazily on first use (not eagerly in the constructor, so a script that never calls `text()`/
|
|
235
|
+
`textmetrics()`/`fontmetrics()` never pays for font parsing). Laziness runs one level deeper too:
|
|
236
|
+
the system font directories are only scanned once a `font=` spec actually names a family, so the
|
|
237
|
+
common case — the default font, or a family already resolved once — never walks the filesystem.
|
|
238
|
+
|
|
239
|
+
The interface is shaped around shaping: `shapeText()` takes a whole string, because kerning,
|
|
240
|
+
ligatures, mark positioning and bidi reordering are properties of the run and not of any character
|
|
241
|
+
in it, and returns positioned *glyph indices* rather than codepoints (the mapping is neither 1:1
|
|
242
|
+
nor stable across fonts). `direction`/`language`/`script` are honoured rather than merely accepted;
|
|
243
|
+
whichever is left empty is filled in by `hb_buffer_guess_segment_properties`, the same job real
|
|
244
|
+
OpenSCAD's `detect_properties()`/`detect_script()` does by hand.
|
|
245
|
+
|
|
246
|
+
`resolveFont()` never fails. An unmatched family falls back to the bundled Liberation Sans
|
|
247
|
+
(`resources/fonts/`, embedded into the binary by `cmake/embed_font.cmake`, byte-identical to the
|
|
248
|
+
Python reference's own bundled font), which is both the default and the last-resort fallback — so
|
|
249
|
+
`text()` draws something even on a machine with no fonts installed at all. That mirrors
|
|
250
|
+
fontconfig's own never-fails matching, and so real OpenSCAD's: a missing font silently becomes the
|
|
251
|
+
nearest available one rather than an error.
|
|
252
|
+
|
|
253
|
+
`font_match.cpp` is the part of fontconfig that `font=` actually needs, reimplemented: comma-
|
|
254
|
+
separated family lists, `:style=Bold Italic` (and bare `:Bold`), other properties ignored rather
|
|
255
|
+
than rejected, generic `sans-serif`/`serif`/`monospace` aliases expanded to concrete families, and
|
|
256
|
+
a recursive scan of the platform font directories plus `OPENSCAD_FONT_PATH` (the same environment
|
|
257
|
+
variable real OpenSCAD reads). Family match is case-insensitive and required; style is a
|
|
258
|
+
*preference* — exact, then substring, then Regular, then the family's first face — because
|
|
259
|
+
dropping to Regular beats falling through to an unrelated family, which is what fontconfig does
|
|
260
|
+
too.
|
|
261
|
+
|
|
262
|
+
`text_metrics.hpp`/`.cpp` holds the shared layout math (`measureText`/`textAlignOffset`) used by
|
|
263
|
+
both `text()` (`builtins/text.cpp`) and `textmetrics()`/`fontmetrics()` (`function_builtins.cpp`).
|
|
264
|
+
Sharing it is the point: the numbers a script positions against cannot disagree with what it
|
|
265
|
+
draws. The `size * (100/72) / unitsPerEm` scale factor reproduces real OpenSCAD's own long-standing
|
|
266
|
+
`text()` size bug (its issue #4304 — `FT_Set_Char_Size` given 100 dpi where 72 is correct, making
|
|
267
|
+
glyphs ~1.39x nominal) deliberately: a decade of models are drawn to it, and OpenSCAD itself chose
|
|
268
|
+
to keep it and add an `em=` parameter rather than fix it.
|
|
243
269
|
|
|
244
270
|
**Debugger/profiler, Phase 9 (the last phase)**: `checkDebug()` fires at **full parity with the
|
|
245
271
|
reference's `_check_debug` call sites** — the statement checkpoint in `evalChildren`'s `runAll`,
|
|
@@ -633,30 +659,39 @@ grep for `ponytail:`.
|
|
|
633
659
|
OpenSCAD up) at the point-transform step, `applyMat()` (named to avoid colliding with
|
|
634
660
|
`std::apply` in an ADL lookup that broke the build once — see its own comment).
|
|
635
661
|
- `include/openscad_cpp_evaluator/font_provider.hpp` — the `FontProvider` abstract interface
|
|
636
|
-
(`resolveFont`/`metrics`/`
|
|
637
|
-
`text()`/`textmetrics()`/`fontmetrics()` decoupled from any specific font backend
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
- `include/openscad_cpp_evaluator/
|
|
643
|
-
|
|
644
|
-
(`
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
`
|
|
662
|
+
(`resolveFont`/`metrics`/`shapeText`/`glyphInkBounds`/`glyphOutline`), the seam that keeps
|
|
663
|
+
`text()`/`textmetrics()`/`fontmetrics()` decoupled from any specific font backend. `Evaluator`'s
|
|
664
|
+
constructor takes an optional injected `shared_ptr<FontProvider>`; `Evaluator::fontProvider()`
|
|
665
|
+
lazily constructs the built-in one (below) on first use otherwise. The seam stays because a host
|
|
666
|
+
that already owns a font stack (a Qt app with `QRawFont`) may prefer to answer these five
|
|
667
|
+
questions itself rather than run a second font engine in the same process.
|
|
668
|
+
- `include/openscad_cpp_evaluator/freetype_font_provider.hpp`,
|
|
669
|
+
`src/text/freetype_font_provider.cpp` — the built-in implementation. HarfBuzz shapes
|
|
670
|
+
(`hb_blob_create_from_file_or_fail` → `hb_face_create` → `hb_font_create` +
|
|
671
|
+
`hb_ot_font_set_funcs`, scaled to unitsPerEm so positions come back in font units); FreeType
|
|
672
|
+
supplies outlines (`FT_LOAD_NO_SCALE` + `FT_Outline_Decompose`, curves flattened uniformly in
|
|
673
|
+
`t` — the same approximation real OpenSCAD's `DrawingCallback` makes) and face metrics
|
|
674
|
+
(`lineGap` derived as `height - (ascender - descender)`, since FreeType reports the summed line
|
|
675
|
+
height). Faces are cached per resolved spec; handle 0 is always the bundled font.
|
|
676
|
+
- `include/openscad_cpp_evaluator/font_match.hpp`, `src/text/font_match.cpp` — the fontconfig
|
|
677
|
+
replacement: `parseFontSpec()` (family list + `:style=`), `expandGenericFamily()`
|
|
678
|
+
(sans-serif/serif/monospace → concrete families), `systemFontDirs()`/`findFontFiles()` (platform
|
|
679
|
+
font directories + `OPENSCAD_FONT_PATH`, `.ttf`/`.otf`/`.ttc`/`.otc`, permission errors skipped
|
|
680
|
+
rather than thrown — a font directory with odd permissions must not take down a render), and
|
|
681
|
+
`matchFace()` (case-insensitive family match required, style preferred). All pure functions over
|
|
682
|
+
plain data, so their tests need no system fonts.
|
|
648
683
|
- `include/openscad_cpp_evaluator/text_metrics.hpp`, `src/text/text_metrics.cpp` — the
|
|
649
684
|
backend-agnostic text-layout math shared by `text()` and `textmetrics()`/`fontmetrics()`:
|
|
650
|
-
`measureText()` (
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
685
|
+
`measureText()` (shapes the run, then aggregates ink-bbox/advance over the positioned glyphs —
|
|
686
|
+
an inkless glyph like a space still advances the pen while contributing nothing to the ink box)
|
|
687
|
+
and `textAlignOffset()` (halign/valign → translation offset).
|
|
688
|
+
- `src/builtins/text.cpp` — `text()` itself: resolves the font and lays the run out via
|
|
689
|
+
`text_metrics.hpp` at resolve time (so `resolveText`'s params carry only plain data — per-glyph
|
|
690
|
+
index + pen x/y, scale, segment count, alignment offset — no `FontProvider`/`EvalContext`
|
|
691
|
+
reference crossing into generate), then at generate time calls `FontProvider::glyphOutline()`
|
|
692
|
+
per glyph, builds each `CrossSection` with the `NonZero` fill rule (what turns a counter wound
|
|
693
|
+
against its outer contour into a hole rather than a second filled blob), unions them, and
|
|
694
|
+
applies the alignment offset.
|
|
660
695
|
- `include/openscad_cpp_evaluator/debug_hooks.hpp`, `include/openscad_cpp_evaluator/profile.hpp`,
|
|
661
696
|
`src/debug_profile.cpp` — the debugging/profiling injection seam. `DebugHookFn`/`ErrorBreakFn`/
|
|
662
697
|
`ReturnHookFn` (bundled into one `DebugHooks` constructor parameter) mirror the reference's
|
|
@@ -129,13 +129,66 @@ FetchContent_Declare(boost_config GIT_REPOSITORY https://github.com/boostorg/con
|
|
|
129
129
|
FetchContent_Declare(boost_polygon GIT_REPOSITORY https://github.com/boostorg/polygon.git GIT_TAG boost-1.86.0 GIT_SHALLOW TRUE)
|
|
130
130
|
FetchContent_MakeAvailable(boost_config boost_polygon)
|
|
131
131
|
|
|
132
|
-
# nothings/stb: single-header stb_image.h
|
|
133
|
-
#
|
|
134
|
-
#
|
|
135
|
-
#
|
|
132
|
+
# nothings/stb: single-header stb_image.h, surface()'s PNG loader -- no
|
|
133
|
+
# build system of its own, just headers, so this only needs an include
|
|
134
|
+
# path, not add_subdirectory/MakeAvailable's target machinery. (It used to
|
|
135
|
+
# supply stb_truetype.h for the font backend too; FreeType/HarfBuzz below
|
|
136
|
+
# replaced that.)
|
|
136
137
|
FetchContent_Declare(stb GIT_REPOSITORY https://github.com/nothings/stb.git GIT_TAG master GIT_SHALLOW TRUE)
|
|
137
138
|
FetchContent_MakeAvailable(stb)
|
|
138
139
|
|
|
140
|
+
# FreeType (glyph outlines + face metrics) and HarfBuzz (shaping), the two
|
|
141
|
+
# halves of the font backend. Both build with plain CMake, which is why
|
|
142
|
+
# they can be FetchContent deps like everything else here -- fontconfig,
|
|
143
|
+
# the third leg of real OpenSCAD's font stack, is meson-only and is
|
|
144
|
+
# deliberately NOT used; font_match.cpp implements its spec syntax and
|
|
145
|
+
# directory scanning directly so that name matching behaves identically on
|
|
146
|
+
# all six wheel targets rather than only where a fontconfig build exists.
|
|
147
|
+
#
|
|
148
|
+
# The two are kept independent of each other on purpose: HB_HAVE_FREETYPE
|
|
149
|
+
# is OFF, so HarfBuzz reads the font through its own hb-ot tables reader
|
|
150
|
+
# rather than through FreeType, and no find_package(Freetype) has to
|
|
151
|
+
# resolve against a FetchContent target that isn't installed anywhere.
|
|
152
|
+
# Both sides address glyphs by the same font-internal glyph index, so the
|
|
153
|
+
# split costs nothing: HarfBuzz shapes text into positioned glyph indices,
|
|
154
|
+
# FreeType turns each index into an outline. Everything crosses that
|
|
155
|
+
# boundary in font units (hb_font_set_scale to unitsPerEm on one side,
|
|
156
|
+
# FT_LOAD_NO_SCALE on the other), so there is no scale mismatch to
|
|
157
|
+
# reconcile either.
|
|
158
|
+
#
|
|
159
|
+
# FreeType's optional dependencies are all disabled: zlib/bzip2/brotli
|
|
160
|
+
# decompress rare embedded-table formats, PNG is for colour bitmap emoji
|
|
161
|
+
# strikes, and HarfBuzz there is only for autohinting quality -- none of
|
|
162
|
+
# which matter when the only thing being asked for is a scalable outline.
|
|
163
|
+
# Leaving them on would make the wheel build depend on whatever those
|
|
164
|
+
# libraries happen to be on six different build images.
|
|
165
|
+
set(FT_DISABLE_ZLIB ON CACHE BOOL "" FORCE)
|
|
166
|
+
set(FT_DISABLE_BZIP2 ON CACHE BOOL "" FORCE)
|
|
167
|
+
set(FT_DISABLE_PNG ON CACHE BOOL "" FORCE)
|
|
168
|
+
set(FT_DISABLE_HARFBUZZ ON CACHE BOOL "" FORCE)
|
|
169
|
+
set(FT_DISABLE_BROTLI ON CACHE BOOL "" FORCE)
|
|
170
|
+
FetchContent_Declare(
|
|
171
|
+
freetype
|
|
172
|
+
GIT_REPOSITORY https://github.com/freetype/freetype.git
|
|
173
|
+
GIT_TAG VER-2-14-3
|
|
174
|
+
GIT_SHALLOW TRUE
|
|
175
|
+
)
|
|
176
|
+
FetchContent_MakeAvailable(freetype)
|
|
177
|
+
|
|
178
|
+
set(HB_HAVE_FREETYPE OFF CACHE BOOL "" FORCE)
|
|
179
|
+
set(HB_HAVE_GLIB OFF CACHE BOOL "" FORCE)
|
|
180
|
+
set(HB_HAVE_ICU OFF CACHE BOOL "" FORCE)
|
|
181
|
+
set(HB_BUILD_SUBSET OFF CACHE BOOL "" FORCE)
|
|
182
|
+
set(HB_BUILD_UTILS OFF CACHE BOOL "" FORCE)
|
|
183
|
+
set(HB_BUILD_TESTS OFF CACHE BOOL "" FORCE)
|
|
184
|
+
FetchContent_Declare(
|
|
185
|
+
harfbuzz
|
|
186
|
+
GIT_REPOSITORY https://github.com/harfbuzz/harfbuzz.git
|
|
187
|
+
GIT_TAG 14.3.1
|
|
188
|
+
GIT_SHALLOW TRUE
|
|
189
|
+
)
|
|
190
|
+
FetchContent_MakeAvailable(harfbuzz)
|
|
191
|
+
|
|
139
192
|
# yhirose/cpp-linenoise: header-only, BSD-2-Clause C++ port of antirez/
|
|
140
193
|
# linenoise with native Windows console support (no ANSI emulation layer,
|
|
141
194
|
# unlike GNU readline's Windows story) -- gives the --debug REPL's real
|
|
@@ -149,7 +202,7 @@ FetchContent_MakeAvailable(cpp_linenoise)
|
|
|
149
202
|
|
|
150
203
|
# Embeds the bundled default font's (resources/fonts/) raw bytes into a
|
|
151
204
|
# generated header (kBundledFontData/kBundledFontDataSize), so
|
|
152
|
-
#
|
|
205
|
+
# FreetypeFontProvider needs no runtime file path for its default font --
|
|
153
206
|
# a real installed/packaged build (e.g. the PyPI wheel) has no guarantee the
|
|
154
207
|
# source tree's resources/fonts/ is present or at any predictable path
|
|
155
208
|
# alongside the installed shared library.
|
|
@@ -63,7 +63,7 @@ public:
|
|
|
63
63
|
// `fontProvider`: injection seam for text()/textmetrics()/fontmetrics()
|
|
64
64
|
// (see font_provider.hpp). Left null (the common case for this repo's
|
|
65
65
|
// own tests/CLI, and for any host that hasn't wired in its own) lazily
|
|
66
|
-
// constructs the built-in
|
|
66
|
+
// constructs the built-in FreetypeFontProvider on first use, not in
|
|
67
67
|
// the constructor -- avoids paying for font-file parsing on every
|
|
68
68
|
// Evaluator even when a script never calls text()/textmetrics().
|
|
69
69
|
// `manifoldCache`: opt-in content-hash cache (see manifold_cache.hpp)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <optional>
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <vector>
|
|
6
|
+
|
|
7
|
+
namespace oscadeval {
|
|
8
|
+
|
|
9
|
+
// A parsed fontconfig-style font spec, which is what OpenSCAD's `font=`
|
|
10
|
+
// takes: a comma-separated family list, then colon-separated properties.
|
|
11
|
+
//
|
|
12
|
+
// "Liberation Sans"
|
|
13
|
+
// "Liberation Sans:style=Bold Italic"
|
|
14
|
+
// "Helvetica,Arial,sans-serif:style=Bold"
|
|
15
|
+
//
|
|
16
|
+
// Only `style=` is meaningful here; fontconfig accepts a long tail of
|
|
17
|
+
// other properties (:size=, :weight=, :lang=) that OpenSCAD models never
|
|
18
|
+
// use, and quietly ignoring them beats rejecting a spec that fontconfig
|
|
19
|
+
// itself would have accepted. A bare `:Bold` (no `=`) is read as a style
|
|
20
|
+
// too, since fontconfig's own parser allows it.
|
|
21
|
+
struct FontSpec {
|
|
22
|
+
std::vector<std::string> families;
|
|
23
|
+
std::string style;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
FontSpec parseFontSpec(const std::string& spec);
|
|
27
|
+
|
|
28
|
+
// Generic family names, expanded to the concrete families likely to be
|
|
29
|
+
// installed. fontconfig resolves these through its own alias config
|
|
30
|
+
// (OpenSCAD ships 10-liberation.conf pointing them at the Liberation
|
|
31
|
+
// faces); with no fontconfig, the alias list lives here instead.
|
|
32
|
+
// Returns an empty vector for a family that isn't generic.
|
|
33
|
+
std::vector<std::string> expandGenericFamily(const std::string& family);
|
|
34
|
+
|
|
35
|
+
// Every directory the platform keeps fonts in, plus anything on
|
|
36
|
+
// OPENSCAD_FONT_PATH (same environment variable real OpenSCAD reads, same
|
|
37
|
+
// platform path separator). Directories that don't exist are dropped, so
|
|
38
|
+
// the result is safe to walk blindly.
|
|
39
|
+
std::vector<std::string> systemFontDirs();
|
|
40
|
+
|
|
41
|
+
// Every font file under those directories: .ttf/.otf/.ttc/.otc, recursive.
|
|
42
|
+
// A directory that can't be read is skipped rather than throwing -- a font
|
|
43
|
+
// directory with odd permissions must not take down a render.
|
|
44
|
+
std::vector<std::string> findFontFiles();
|
|
45
|
+
|
|
46
|
+
// One face inside one font file. A .ttc collection holds several, hence
|
|
47
|
+
// the index; a plain .ttf is always index 0.
|
|
48
|
+
struct FontFace {
|
|
49
|
+
std::string path;
|
|
50
|
+
int faceIndex = 0;
|
|
51
|
+
std::string family;
|
|
52
|
+
std::string style;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Best match for `spec` among `faces`, or nullopt if no requested family
|
|
56
|
+
// (after generic expansion) is present at all. Family match is
|
|
57
|
+
// case-insensitive and required; style is a preference, not a filter,
|
|
58
|
+
// resolved in the order: exact style, then substring, then "Regular",
|
|
59
|
+
// then the first face of that family.
|
|
60
|
+
std::optional<FontFace> matchFace(const FontSpec& spec, const std::vector<FontFace>& faces);
|
|
61
|
+
|
|
62
|
+
} // namespace oscadeval
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <array>
|
|
4
|
+
#include <cstdint>
|
|
5
|
+
#include <optional>
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <vector>
|
|
8
|
+
|
|
9
|
+
namespace oscadeval {
|
|
10
|
+
|
|
11
|
+
using FontHandle = std::uint64_t;
|
|
12
|
+
|
|
13
|
+
// A font-internal glyph index, NOT a Unicode codepoint. Shaping is what
|
|
14
|
+
// turns one into the other, and the mapping is neither 1:1 nor stable
|
|
15
|
+
// across fonts: one codepoint can shape to several glyphs, several
|
|
16
|
+
// codepoints can shape to one ligature glyph, and the same character has a
|
|
17
|
+
// different index in every font.
|
|
18
|
+
using GlyphId = std::uint32_t;
|
|
19
|
+
|
|
20
|
+
// Global (whole-font) metrics, all in font units (not yet scaled for a
|
|
21
|
+
// particular `size=`) -- mirrors fontmetrics()'s "nominal"/"max" split:
|
|
22
|
+
// ascent/descent/lineGap come from the font's hhea table (or equivalent),
|
|
23
|
+
// yMax/yMin from its head table (or equivalent) -- these commonly differ
|
|
24
|
+
// (yMax/yMin bound the tallest/deepest glyph actually in the font; ascent/
|
|
25
|
+
// descent are the font designer's nominal line-layout values).
|
|
26
|
+
struct FontMetrics {
|
|
27
|
+
double unitsPerEm = 1000.0;
|
|
28
|
+
double ascent = 0, descent = 0, lineGap = 0;
|
|
29
|
+
double yMax = 0, yMin = 0;
|
|
30
|
+
std::string family, style;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// One glyph as placed by the shaper, in font units. `xOffset`/`yOffset`
|
|
34
|
+
// adjust this glyph's own position without moving the pen (mark
|
|
35
|
+
// attachment, cursive joins); `xAdvance`/`yAdvance` move the pen. Both are
|
|
36
|
+
// shaping output, not raw hmtx values -- kerning and ligature
|
|
37
|
+
// substitutions are already applied by the time this exists.
|
|
38
|
+
struct ShapedGlyph {
|
|
39
|
+
GlyphId glyph = 0;
|
|
40
|
+
double xOffset = 0, yOffset = 0;
|
|
41
|
+
double xAdvance = 0, yAdvance = 0;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// What OpenSCAD's text()/textmetrics() call direction/language/script.
|
|
45
|
+
// Any field left empty is guessed from the text itself by the shaper,
|
|
46
|
+
// which is what real OpenSCAD's detect_properties() does by hand.
|
|
47
|
+
struct ShapeOptions {
|
|
48
|
+
std::string direction; // "ltr", "rtl", "ttb", "btt"
|
|
49
|
+
std::string language; // BCP 47, e.g. "en"
|
|
50
|
+
std::string script; // ISO 15924, e.g. "Latn", "Arab"
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// Flattened polyline contours (curves already split into straight
|
|
54
|
+
// segments), in font units.
|
|
55
|
+
using GlyphContours = std::vector<std::vector<std::array<double, 2>>>;
|
|
56
|
+
|
|
57
|
+
// Abstraction over font resolution/shaping/outline extraction, so
|
|
58
|
+
// text()/textmetrics()/fontmetrics() don't hard-depend on a specific font
|
|
59
|
+
// backend. The library ships FreetypeFontProvider (HarfBuzz for shaping,
|
|
60
|
+
// FreeType for outlines and face metrics, and its own fontconfig-syntax
|
|
61
|
+
// matcher for system fonts) as the built-in default, which is what every
|
|
62
|
+
// build here actually uses; the interface stays because a host that
|
|
63
|
+
// already owns a font stack (a Qt app with QRawFont, say) may prefer to
|
|
64
|
+
// answer these five questions itself rather than have a second font
|
|
65
|
+
// engine resolving names in the same process.
|
|
66
|
+
class FontProvider {
|
|
67
|
+
public:
|
|
68
|
+
virtual ~FontProvider() = default;
|
|
69
|
+
|
|
70
|
+
// Resolves an OpenSCAD/fontconfig-style spec (e.g. "Times New
|
|
71
|
+
// Roman:style=Bold", or "" for the default) to an opaque handle.
|
|
72
|
+
// Never fails: an unmatched spec falls back to the default font,
|
|
73
|
+
// matching fontconfig's own never-fails matching (and so real
|
|
74
|
+
// OpenSCAD's), where a missing font silently becomes the nearest
|
|
75
|
+
// available one rather than an error.
|
|
76
|
+
virtual FontHandle resolveFont(const std::string& spec) = 0;
|
|
77
|
+
|
|
78
|
+
virtual FontMetrics metrics(FontHandle handle) = 0;
|
|
79
|
+
|
|
80
|
+
// Lays out a whole string at once -- not per codepoint, because
|
|
81
|
+
// kerning, ligatures, mark positioning and bidi reordering are all
|
|
82
|
+
// properties of the run rather than of any character in it.
|
|
83
|
+
virtual std::vector<ShapedGlyph> shapeText(FontHandle handle, const std::string& utf8,
|
|
84
|
+
const ShapeOptions& opts) = 0;
|
|
85
|
+
|
|
86
|
+
// The glyph's ink bounding box (xMin, yMin, xMax, yMax) in font units,
|
|
87
|
+
// or nullopt for a glyph that draws nothing (a space, or a .notdef
|
|
88
|
+
// with an empty outline) -- such a glyph still advances the pen, so it
|
|
89
|
+
// affects `advance` while contributing nothing to the ink box that
|
|
90
|
+
// textmetrics() reports as position/size.
|
|
91
|
+
virtual std::optional<std::array<double, 4>> glyphInkBounds(FontHandle handle, GlyphId glyph) = 0;
|
|
92
|
+
|
|
93
|
+
// Only called by text() itself (rendering) -- textmetrics()/
|
|
94
|
+
// fontmetrics() need only the two calls above.
|
|
95
|
+
virtual GlyphContours glyphOutline(FontHandle handle, GlyphId glyph, int segsPerCurve) = 0;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
} // namespace oscadeval
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "openscad_cpp_evaluator/font_provider.hpp"
|
|
4
|
+
|
|
5
|
+
#include <memory>
|
|
6
|
+
|
|
7
|
+
namespace oscadeval {
|
|
8
|
+
|
|
9
|
+
// The built-in FontProvider: HarfBuzz shapes, FreeType supplies outlines
|
|
10
|
+
// and face metrics, and font_match.cpp resolves `font=` specs against the
|
|
11
|
+
// platform's font directories. No fontconfig -- see the CMakeLists note on
|
|
12
|
+
// why, and font_match.hpp for what of its behaviour is reimplemented.
|
|
13
|
+
//
|
|
14
|
+
// The bundled Liberation Sans (resources/fonts/, embedded into the binary
|
|
15
|
+
// by cmake/embed_font.cmake) is the default font and the last-resort
|
|
16
|
+
// fallback, so `text()` always draws something even on a machine with no
|
|
17
|
+
// fonts installed at all -- the same font real OpenSCAD falls back to.
|
|
18
|
+
//
|
|
19
|
+
// Font files are opened lazily and cached per resolved spec: a script that
|
|
20
|
+
// never calls text()/textmetrics()/fontmetrics() opens nothing, and one
|
|
21
|
+
// that only uses the default font never scans a system directory.
|
|
22
|
+
class FreetypeFontProvider : public FontProvider {
|
|
23
|
+
public:
|
|
24
|
+
FreetypeFontProvider();
|
|
25
|
+
~FreetypeFontProvider() override;
|
|
26
|
+
|
|
27
|
+
FontHandle resolveFont(const std::string& spec) override;
|
|
28
|
+
FontMetrics metrics(FontHandle handle) override;
|
|
29
|
+
std::vector<ShapedGlyph> shapeText(FontHandle handle, const std::string& utf8, const ShapeOptions& opts) override;
|
|
30
|
+
std::optional<std::array<double, 4>> glyphInkBounds(FontHandle handle, GlyphId glyph) override;
|
|
31
|
+
GlyphContours glyphOutline(FontHandle handle, GlyphId glyph, int segsPerCurve) override;
|
|
32
|
+
|
|
33
|
+
private:
|
|
34
|
+
struct Impl;
|
|
35
|
+
std::unique_ptr<Impl> impl_;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
} // namespace oscadeval
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "openscad_cpp_evaluator/font_provider.hpp"
|
|
4
|
+
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <utility>
|
|
7
|
+
#include <vector>
|
|
8
|
+
|
|
9
|
+
namespace oscadeval {
|
|
10
|
+
|
|
11
|
+
// Layout of `text`'s ink-bbox/advance metrics, in OpenSCAD units scaled
|
|
12
|
+
// for `size`. `glyphs` is what text() places: each shaped glyph with its
|
|
13
|
+
// pen position, already scaled. An inkless glyph (a space) still advances
|
|
14
|
+
// the pen and still gets a glyphs entry -- it just contributes nothing to
|
|
15
|
+
// ascent/descent/inkMinX/inkMaxX.
|
|
16
|
+
//
|
|
17
|
+
// The run comes from the shaper, so kerning and ligatures are already
|
|
18
|
+
// applied and `spacing` scales the shaped advances rather than raw
|
|
19
|
+
// per-character widths.
|
|
20
|
+
struct TextMeasurement {
|
|
21
|
+
struct Placed {
|
|
22
|
+
GlyphId glyph = 0;
|
|
23
|
+
double x = 0, y = 0;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
double ascent = 0, descent = 0, inkMinX = 0, inkMaxX = 0;
|
|
27
|
+
double advanceX = 0, advanceY = 0;
|
|
28
|
+
std::vector<Placed> glyphs;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
TextMeasurement measureText(FontProvider& fp, FontHandle handle, const std::string& text, double size,
|
|
32
|
+
double spacing, const ShapeOptions& opts = {});
|
|
33
|
+
|
|
34
|
+
// (offsetX, offsetY) translation for halign/valign, given a
|
|
35
|
+
// TextMeasurement. Shared by textmetrics() (reports it) and text()
|
|
36
|
+
// (applies it).
|
|
37
|
+
std::pair<double, double> textAlignOffset(const std::string& halign, const std::string& valign,
|
|
38
|
+
const TextMeasurement& m);
|
|
39
|
+
|
|
40
|
+
} // namespace oscadeval
|
|
@@ -21,7 +21,8 @@ add_library(openscad_cpp_evaluator STATIC
|
|
|
21
21
|
import/surface_load.cpp
|
|
22
22
|
import/dxf_import.cpp
|
|
23
23
|
import/svg_import.cpp
|
|
24
|
-
text/
|
|
24
|
+
text/freetype_font_provider.cpp
|
|
25
|
+
text/font_match.cpp
|
|
25
26
|
text/text_metrics.cpp
|
|
26
27
|
debug/debug_repl.cpp
|
|
27
28
|
builtins/text.cpp
|
|
@@ -51,7 +52,7 @@ target_include_directories(openscad_cpp_evaluator PRIVATE ${stb_SOURCE_DIR} ${CM
|
|
|
51
52
|
add_dependencies(openscad_cpp_evaluator generate_bundled_font)
|
|
52
53
|
|
|
53
54
|
target_link_libraries(openscad_cpp_evaluator PUBLIC openscad_cpp_parser manifold Boost::polygon)
|
|
54
|
-
target_link_libraries(openscad_cpp_evaluator PRIVATE linenoise)
|
|
55
|
+
target_link_libraries(openscad_cpp_evaluator PRIVATE linenoise freetype harfbuzz)
|
|
55
56
|
target_compile_options(openscad_cpp_evaluator PRIVATE
|
|
56
57
|
$<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-Wall;-Wextra>
|
|
57
58
|
)
|
{openscad_cpp_evaluator-0.31.2 → openscad_cpp_evaluator-0.32.2}/src/builtins/function_builtins.cpp
RENAMED
|
@@ -320,10 +320,13 @@ Value objectOf(std::vector<std::pair<std::string, Value>> items) {
|
|
|
320
320
|
return Value{std::make_shared<const ValueObject>(ValueObject{std::move(items)})};
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
-
// textmetrics(text=, size=10,
|
|
324
|
-
// `text` against the
|
|
325
|
-
//
|
|
326
|
-
//
|
|
323
|
+
// textmetrics(text=, size=10, font=, direction=, language=, script=,
|
|
324
|
+
// halign=, valign=, spacing=) -- measures `text` against the
|
|
325
|
+
// FontProvider-resolved font, laid out by exactly the same shaping call
|
|
326
|
+
// text() makes, and returns an OscObject with position/size/ascent/
|
|
327
|
+
// descent/offset/advance in real OpenSCAD's key order. Going through the
|
|
328
|
+
// same measureText() the geometry goes through is the point: the numbers
|
|
329
|
+
// a script positions against cannot disagree with what it draws.
|
|
327
330
|
Value builtinTextmetrics(Evaluator& ev, const CallArgs& args) {
|
|
328
331
|
const std::string text = asStringOr(getArg(args, 0, "text", Value{std::string("")}), "");
|
|
329
332
|
const double size = toDoubleLenient(getArg(args, 1, "size", Value{10.0}));
|
|
@@ -331,10 +334,14 @@ Value builtinTextmetrics(Evaluator& ev, const CallArgs& args) {
|
|
|
331
334
|
const std::string valign = asStringOr(getArg(args, std::nullopt, "valign", Value{std::string("baseline")}), "baseline");
|
|
332
335
|
const double spacing = toDoubleLenient(getArg(args, std::nullopt, "spacing", Value{1.0}));
|
|
333
336
|
const std::string fontSpec = asStringOr(getArg(args, std::nullopt, "font", Value{std::string("")}), "");
|
|
337
|
+
ShapeOptions shape;
|
|
338
|
+
shape.direction = asStringOr(getArg(args, std::nullopt, "direction", Value{std::string("")}), "");
|
|
339
|
+
shape.language = asStringOr(getArg(args, std::nullopt, "language", Value{std::string("")}), "");
|
|
340
|
+
shape.script = asStringOr(getArg(args, std::nullopt, "script", Value{std::string("")}), "");
|
|
334
341
|
|
|
335
342
|
FontProvider& fp = ev.fontProvider();
|
|
336
343
|
const FontHandle handle = fp.resolveFont(fontSpec);
|
|
337
|
-
const TextMeasurement m = measureText(fp, handle, text, size, spacing);
|
|
344
|
+
const TextMeasurement m = measureText(fp, handle, text, size, spacing, shape);
|
|
338
345
|
const auto [offsetX, offsetY] = textAlignOffset(halign, valign, m);
|
|
339
346
|
|
|
340
347
|
return objectOf({
|
|
@@ -343,7 +350,7 @@ Value builtinTextmetrics(Evaluator& ev, const CallArgs& args) {
|
|
|
343
350
|
{"ascent", Value{m.ascent}},
|
|
344
351
|
{"descent", Value{m.descent}},
|
|
345
352
|
{"offset", numList({offsetX, offsetY})},
|
|
346
|
-
{"advance", numList({m.advanceX,
|
|
353
|
+
{"advance", numList({m.advanceX, m.advanceY})},
|
|
347
354
|
});
|
|
348
355
|
}
|
|
349
356
|
|
|
@@ -684,8 +691,29 @@ Value evalBuiltinFunction(Evaluator& ev, const std::string& name, const CallArgs
|
|
|
684
691
|
}
|
|
685
692
|
return Value{false};
|
|
686
693
|
}
|
|
687
|
-
|
|
688
|
-
|
|
694
|
+
// The OpenSCAD release we track. version_num() is that same
|
|
695
|
+
// year/month/day folded as y * 10000 + m * 100 + d, exactly like the
|
|
696
|
+
// reference's own builtin_version_num (builtin_functions.cc).
|
|
697
|
+
case BuiltinFnId::Version: return numList({2026.0, 1.0, 1.0});
|
|
698
|
+
case BuiltinFnId::VersionNum: {
|
|
699
|
+
// The optional vector argument the reference also accepts: with
|
|
700
|
+
// no argument this is our own version() folded; with one, it is
|
|
701
|
+
// whatever [y, m] / [y, m, d] the caller passed, so
|
|
702
|
+
// version_num([2019, 5, 0]) == 20190500 regardless of what
|
|
703
|
+
// release we report. A 2-element vector defaults the day to 0
|
|
704
|
+
// (getVec3's own defaultval), and anything else -- a non-list, a
|
|
705
|
+
// wrong length, a non-numeric element -- is undef.
|
|
706
|
+
//
|
|
707
|
+
// One deliberate divergence: the reference's size-2 path ignores
|
|
708
|
+
// getVec2's own failure and folds uninitialized doubles for e.g.
|
|
709
|
+
// version_num(["a", "b"]). That is undef here rather than
|
|
710
|
+
// whatever happened to be on the stack.
|
|
711
|
+
const Value* arg = args.findPositional(0);
|
|
712
|
+
if (!arg) return Value{20260101.0};
|
|
713
|
+
const auto v = allNumericList(*arg);
|
|
714
|
+
if (!v || (v->size() != 2 && v->size() != 3)) return Value{};
|
|
715
|
+
return Value{(*v)[0] * 10000.0 + (*v)[1] * 100.0 + (v->size() == 3 ? (*v)[2] : 0.0)};
|
|
716
|
+
}
|
|
689
717
|
case BuiltinFnId::ParentModule:
|
|
690
718
|
return ev.parentModuleName(static_cast<int>(toDoubleLenient(getArg(args, 0, "index", Value{0.0}))));
|
|
691
719
|
}
|