openscad-cpp-evaluator 1.10.0__tar.gz → 1.12.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.10.0 → openscad_cpp_evaluator-1.12.0}/CLAUDE.md +30 -2
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/bindings/module.cpp +51 -2
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/export.hpp +64 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/zip_stored.hpp +8 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/python/openscad_cpp_evaluator/__init__.py +14 -2
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/booleans.cpp +81 -14
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/export.cpp +378 -14
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/zip_stored.cpp +10 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_booleans.cpp +115 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_export.cpp +293 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_python_bindings.py +44 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/.github/workflows/wheels.yml +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/README.md +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.10.0 → openscad_cpp_evaluator-1.12.0}/uv.lock +0 -0
|
@@ -793,6 +793,18 @@ grep for `ponytail:`.
|
|
|
793
793
|
color instead of preserving each part's own, matching real OpenSCAD's actual behavior once fixed
|
|
794
794
|
(cross-checked triangle-color-count-and-values against the Python reference directly, not just
|
|
795
795
|
“does it run”).
|
|
796
|
+
**2D cannot use any of that, and keeps colour geometrically instead** (`Part2d`, same file): a
|
|
797
|
+
`CrossSection` is contours, not a mesh, so nothing in it remembers which child an edge came from
|
|
798
|
+
and there is no provenance for `attachTriColors` to read back. So the 2D accumulator holds **one
|
|
799
|
+
part per colour** rather than one merged section — same-coloured children still merge into one
|
|
800
|
+
part, a later statement notches what it covers out of the earlier parts (painter's order, the
|
|
801
|
+
rule `splitBodiesForExport` applies to overlapping 3D solids), `difference`/`intersection` apply
|
|
802
|
+
to every part, and a part cut away entirely is dropped. `generateCsg` then returns one
|
|
803
|
+
`ColoredBody` per surviving part, so **a 2D `union()` of differently-coloured children returns
|
|
804
|
+
several bodies where it used to return one**. Reported as a user bug: `union() { color("red")
|
|
805
|
+
square(10); color("blue") translate([12,0]) square(10); }` drew both squares red, where OpenSCAD
|
|
806
|
+
draws red and blue (verified by pixel-sampling both binaries' PNG output). `linear_extrude` of
|
|
807
|
+
such a union still drops colour entirely — checked against the real binary, which does the same.
|
|
796
808
|
- `src/builtins/primitives_3d.cpp` — `sphere(style=)` is a BelfrySCAD extension naming the
|
|
797
809
|
tessellation, using BOSL2's five `spheroid()` style names and constructions: `"orig"` (the default,
|
|
798
810
|
and what OpenSCAD's own sphere() builds — rings offset half a step from the poles, no pole vertex),
|
|
@@ -916,8 +928,8 @@ grep for `ponytail:`.
|
|
|
916
928
|
— skip it and the mesh comes out non-manifold at the seam). Self-contained 2D geometry math here
|
|
917
929
|
(`dot2`/`len2`/`norm2`, the parabola-canonical-frame rotation in `discretizeArc`) exists nowhere
|
|
918
930
|
else in this codebase.
|
|
919
|
-
- `include/openscad_cpp_evaluator/export.hpp`, `src/export.cpp` — the writers for all
|
|
920
|
-
formats `exportExtensions()` lists: 3MF, AMF, STL, OBJ, OFF, PLY, SVG, VRML, X3D (3MF via
|
|
931
|
+
- `include/openscad_cpp_evaluator/export.hpp`, `src/export.cpp` — the writers for all ten
|
|
932
|
+
formats `exportExtensions()` lists: 3MF, AMF, PDF, STL, OBJ, OFF, PLY, SVG, VRML, X3D (3MF via
|
|
921
933
|
`zip_stored.hpp`'s `writeDeflateZip`). **`exportExtensions()` is the one source of truth for
|
|
922
934
|
which formats exist** — the Python facade and BelfrySCAD's dialog/CLI all ask it rather than
|
|
923
935
|
restating the list, because three hand-written copies had already drifted far enough that `.off`
|
|
@@ -937,6 +949,22 @@ grep for `ponytail:`.
|
|
|
937
949
|
binary's, vertex order and 6-vertex line wrap included. A 3D body in the list throws
|
|
938
950
|
("Current top level object is not a 2D object"), as OpenSCAD refuses too: there is no projection
|
|
939
951
|
to fall back on. `ExportOptions::svg` carries OpenSCAD's five `-O export-svg/...` settings.
|
|
952
|
+
**`writePdf` is the other 2D writer**, and shares `collect2d()` with `writeSvg` so the all-2D
|
|
953
|
+
rule and its refusal have one implementation. Everything else differs from SVG: the drawing is
|
|
954
|
+
**centred on a fixed paper size** rather than the page being cut to fit, and **PDF user space is
|
|
955
|
+
Y-up like the model's, so there is NO Y negation** — `pt = mm * 72/25.4` plus a centring offset,
|
|
956
|
+
symmetric in both axes. (OpenSCAD's own file negates Y only because Cairo draws Y-down and then
|
|
957
|
+
flips the whole page; its centring is also a fraction of a point off, because it truncates the
|
|
958
|
+
span to an `int` — a bug, not a spec, so ours centres exactly.) With `showScale` it draws
|
|
959
|
+
OpenSCAD's ruler: two axes at a 30pt margin, ticks every **10mm of model space** (hard-coded —
|
|
960
|
+
`gridSize` drives only the optional grid), labels on every second tick, and the caption telling
|
|
961
|
+
you what to measure. That ruler is the point of the format: it is what lets a printed page reveal
|
|
962
|
+
a printer's scaling error. Text is the **base-14 `/Helvetica`** every reader supplies, so nothing
|
|
963
|
+
is embedded and no font metrics are needed — Cairo's subset-embedded font is a Cairo habit, not a
|
|
964
|
+
PDF requirement, and skipping it is what turned this from a project into a writer. The content
|
|
965
|
+
stream is Flate-compressed through `zip_stored.hpp`'s `zlibCompress` (PDF's `/FlateDecode` *is* a
|
|
966
|
+
zlib stream), falling back to raw when that would not shrink it. `writePdf` returns warnings
|
|
967
|
+
rather than `void`: a model too big for the page is drawn anyway and said so.
|
|
940
968
|
`colored_body.hpp`/`.cpp`'s `toRenderableBodies()` (thin-extrudes any top-level 2D-only result to
|
|
941
969
|
a 1-unit-tall `flatPreview` Manifold) must run on a body list before handing it to any of the
|
|
942
970
|
MESH writers — none of them look at `ColoredBody::section` at all, only `.body`. Not before
|
|
@@ -356,13 +356,56 @@ struct Geometry {
|
|
|
356
356
|
|
|
357
357
|
// exportModel, with the path/format/warnings marshalling. Releases the GIL:
|
|
358
358
|
// a large export is seconds of Manifold work with no Python involved.
|
|
359
|
+
// The PDF option set is big enough (paper size, orientation, four
|
|
360
|
+
// ruler switches, fill/stroke, four metadata fields) that a dict keyed the
|
|
361
|
+
// way OpenSCAD names its own `-O export-pdf/...` settings is kinder than
|
|
362
|
+
// fourteen keyword arguments. Unknown keys raise rather than being ignored
|
|
363
|
+
// -- a silently dropped "paper-size" would print the wrong page size with
|
|
364
|
+
// nothing to explain it.
|
|
365
|
+
void applyPdfOptions(const nb::dict& d, oscadeval::ExportPdfOptions& pdf) {
|
|
366
|
+
for (auto item : d) {
|
|
367
|
+
const std::string key = nb::cast<std::string>(item.first);
|
|
368
|
+
const nb::handle v = item.second;
|
|
369
|
+
if (key == "paper-size") {
|
|
370
|
+
const std::string name = nb::cast<std::string>(v);
|
|
371
|
+
if (!oscadeval::paperFromName(name, pdf.paper))
|
|
372
|
+
throw std::runtime_error("unknown paper-size '" + name +
|
|
373
|
+
"' (a6, a5, a4, a3, letter, legal, tabloid)");
|
|
374
|
+
} else if (key == "orientation") {
|
|
375
|
+
const std::string name = nb::cast<std::string>(v);
|
|
376
|
+
if (!oscadeval::orientationFromName(name, pdf.orientation))
|
|
377
|
+
throw std::runtime_error("unknown orientation '" + name + "' (portrait, landscape, auto)");
|
|
378
|
+
} else if (key == "show-scale") pdf.showScale = nb::cast<bool>(v);
|
|
379
|
+
else if (key == "show-scale-message") pdf.showScaleMsg = nb::cast<bool>(v);
|
|
380
|
+
else if (key == "show-grid") pdf.showGrid = nb::cast<bool>(v);
|
|
381
|
+
else if (key == "grid-size") pdf.gridSize = nb::cast<double>(v);
|
|
382
|
+
else if (key == "show-filename") pdf.showFilename = nb::cast<bool>(v);
|
|
383
|
+
else if (key == "design-filename") pdf.designFilename = nb::cast<std::string>(v);
|
|
384
|
+
else if (key == "fill") pdf.fill = nb::cast<bool>(v);
|
|
385
|
+
else if (key == "fill-color") pdf.fillColor = nb::cast<std::string>(v);
|
|
386
|
+
else if (key == "stroke") pdf.stroke = nb::cast<bool>(v);
|
|
387
|
+
else if (key == "stroke-color") pdf.strokeColor = nb::cast<std::string>(v);
|
|
388
|
+
else if (key == "stroke-width") pdf.strokeWidth = nb::cast<double>(v);
|
|
389
|
+
else if (key == "add-meta-data") pdf.addMetaData = nb::cast<bool>(v);
|
|
390
|
+
else if (key == "title") pdf.metaTitle = nb::cast<std::string>(v);
|
|
391
|
+
else if (key == "author") pdf.metaAuthor = nb::cast<std::string>(v);
|
|
392
|
+
else if (key == "subject") pdf.metaSubject = nb::cast<std::string>(v);
|
|
393
|
+
else if (key == "keywords") pdf.metaKeywords = nb::cast<std::string>(v);
|
|
394
|
+
else throw std::runtime_error("unknown pdf option '" + key + "'");
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
359
398
|
nb::list exportModelPy(const std::string& path, const Geometry& geom, const std::string& format, bool asciiStl,
|
|
360
399
|
bool stripSlivers, bool splitComponents, bool svgFill, const std::string& svgFillColor,
|
|
361
|
-
bool svgStroke, const std::string& svgStrokeColor, double svgStrokeWidth
|
|
400
|
+
bool svgStroke, const std::string& svgStrokeColor, double svgStrokeWidth,
|
|
401
|
+
nb::object pdfOptions) {
|
|
402
|
+
oscadeval::ExportPdfOptions pdf;
|
|
403
|
+
if (!pdfOptions.is_none()) applyPdfOptions(nb::cast<nb::dict>(pdfOptions), pdf);
|
|
362
404
|
std::vector<std::string> warnings;
|
|
363
405
|
{
|
|
364
406
|
nb::gil_scoped_release rel;
|
|
365
407
|
oscadeval::ExportOptions opts;
|
|
408
|
+
opts.pdf = pdf;
|
|
366
409
|
opts.format = format;
|
|
367
410
|
opts.asciiStl = asciiStl;
|
|
368
411
|
opts.stripSlivers = stripSlivers;
|
|
@@ -802,6 +845,7 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
802
845
|
nb::arg("split_components") = false, nb::arg("svg_fill") = false,
|
|
803
846
|
nb::arg("svg_fill_color") = std::string("white"), nb::arg("svg_stroke") = true,
|
|
804
847
|
nb::arg("svg_stroke_color") = std::string("black"), nb::arg("svg_stroke_width") = 0.35,
|
|
848
|
+
nb::arg("pdf_options") = nb::none(),
|
|
805
849
|
"Write `geometry` to `path`, format taken from the extension unless `format` says otherwise. "
|
|
806
850
|
"Returns the warnings to surface (open shells, mesh problems, slivers removed) rather than "
|
|
807
851
|
"logging them. Raises RuntimeError when there is no geometry, the format is unknown, or the "
|
|
@@ -811,7 +855,12 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
811
855
|
"per colour however many pieces it is in.\n\n"
|
|
812
856
|
"The svg_* arguments are OpenSCAD's -O export-svg/... set and apply to .svg only. "
|
|
813
857
|
"svg_stroke/svg_stroke_width also pad the page, so they are not purely cosmetic. An .svg "
|
|
814
|
-
"export needs an all-2D model and raises otherwise, as OpenSCAD does
|
|
858
|
+
"export needs an all-2D model and raises otherwise, as OpenSCAD does.\n\n"
|
|
859
|
+
"pdf_options is a dict keyed as OpenSCAD names its -O export-pdf/... settings "
|
|
860
|
+
"(paper-size, orientation, show-scale, show-scale-message, show-grid, grid-size, "
|
|
861
|
+
"show-filename, design-filename, fill, fill-color, stroke, stroke-color, stroke-width, "
|
|
862
|
+
"add-meta-data, title, author, subject, keywords). An unknown key raises rather than "
|
|
863
|
+
"being ignored. .pdf is 2D-only too, and centres the drawing on a fixed paper size.");
|
|
815
864
|
|
|
816
865
|
m.def("export_extensions", []() { return oscadeval::exportExtensions(); },
|
|
817
866
|
"The file extensions export_model understands, dot-prefixed. Read from the C++ writer table "
|
|
@@ -157,6 +157,68 @@ struct ExportSvgOptions {
|
|
|
157
157
|
void writeSvg(const std::string& path, const std::vector<ColoredBody>& bodies,
|
|
158
158
|
const ExportSvgOptions& opts = {});
|
|
159
159
|
|
|
160
|
+
// Options for the PDF writer, named and defaulted after OpenSCAD's own
|
|
161
|
+
// `-O export-pdf/...` set.
|
|
162
|
+
struct ExportPdfOptions {
|
|
163
|
+
enum class Paper { A6, A5, A4, A3, Letter, Legal, Tabloid };
|
|
164
|
+
// AUTO picks landscape when the model is wider than it is tall.
|
|
165
|
+
enum class Orientation { Portrait, Landscape, Auto };
|
|
166
|
+
|
|
167
|
+
Paper paper = Paper::A4;
|
|
168
|
+
Orientation orientation = Orientation::Portrait;
|
|
169
|
+
// The ruler, its labels and the caption that explains them. This is
|
|
170
|
+
// what makes a printed page a measuring tool rather than a plot, and
|
|
171
|
+
// is why the format was asked for at all.
|
|
172
|
+
bool showScale = true;
|
|
173
|
+
bool showScaleMsg = true;
|
|
174
|
+
bool showGrid = false;
|
|
175
|
+
double gridSize = 10.0;
|
|
176
|
+
// Drawn bottom-left when set. The DESIGN's name -- the writer has no
|
|
177
|
+
// way to know it, so a caller that wants it must pass it.
|
|
178
|
+
bool showFilename = false;
|
|
179
|
+
std::string designFilename;
|
|
180
|
+
bool fill = false;
|
|
181
|
+
std::string fillColor = "black";
|
|
182
|
+
bool stroke = true;
|
|
183
|
+
std::string strokeColor = "black";
|
|
184
|
+
double strokeWidth = 0.35;
|
|
185
|
+
bool addMetaData = true;
|
|
186
|
+
std::string metaTitle;
|
|
187
|
+
std::string metaAuthor;
|
|
188
|
+
std::string metaSubject;
|
|
189
|
+
std::string metaKeywords;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
// "a4"/"letter"/... (case-insensitive) -> Paper. Returns false for a name
|
|
193
|
+
// it does not know, leaving `out` untouched.
|
|
194
|
+
bool paperFromName(const std::string& name, ExportPdfOptions::Paper& out);
|
|
195
|
+
// "portrait"/"landscape"/"auto" -> Orientation, same contract.
|
|
196
|
+
bool orientationFromName(const std::string& name, ExportPdfOptions::Orientation& out);
|
|
197
|
+
|
|
198
|
+
// PDF 1.4 of a 2D-only model, drawn at 1:1 and CENTRED on a fixed paper
|
|
199
|
+
// size -- unlike SVG, where the page is cut to fit the model.
|
|
200
|
+
//
|
|
201
|
+
// PDF user space is Y-up like model space, so unlike writeSvg there is NO
|
|
202
|
+
// Y negation: the placement is `pt = mm * 72/25.4` plus a centring offset,
|
|
203
|
+
// symmetric in both axes. (OpenSCAD's own file negates Y only because
|
|
204
|
+
// Cairo draws Y-down and then flips the whole page.)
|
|
205
|
+
//
|
|
206
|
+
// With `showScale` on it also draws OpenSCAD's ruler: a left and bottom
|
|
207
|
+
// axis at a 30pt margin, ticks every 10mm of MODEL space (hard-coded --
|
|
208
|
+
// `gridSize` belongs to the optional grid, not to this), numeric labels on
|
|
209
|
+
// every second tick, and the caption explaining what to measure. That
|
|
210
|
+
// ruler is the point of the format: it is what lets a printed page tell
|
|
211
|
+
// you how far off your printer's scaling is.
|
|
212
|
+
//
|
|
213
|
+
// Text uses the base-14 Helvetica every PDF reader supplies, so nothing is
|
|
214
|
+
// embedded and no font metrics are needed.
|
|
215
|
+
//
|
|
216
|
+
// Returns the warnings to surface (a model too large for the page is drawn
|
|
217
|
+
// anyway, and said so). Throws std::runtime_error if any top-level body is
|
|
218
|
+
// 3D, if there is nothing to draw, or if the file cannot be opened.
|
|
219
|
+
std::vector<std::string> writePdf(const std::string& path, const std::vector<ColoredBody>& bodies,
|
|
220
|
+
const ExportPdfOptions& opts = {});
|
|
221
|
+
|
|
160
222
|
// -- one entry point ------------------------------------------------------
|
|
161
223
|
|
|
162
224
|
struct ExportOptions {
|
|
@@ -176,6 +238,8 @@ struct ExportOptions {
|
|
|
176
238
|
bool splitComponents = false;
|
|
177
239
|
// .svg only.
|
|
178
240
|
ExportSvgOptions svg;
|
|
241
|
+
// .pdf only.
|
|
242
|
+
ExportPdfOptions pdf;
|
|
179
243
|
};
|
|
180
244
|
|
|
181
245
|
// Writes `bodies` to `path`, choosing the writer from the extension (or
|
|
@@ -28,6 +28,14 @@ void writeStoredZip(const std::string& path, const std::vector<ZipEntry>& entrie
|
|
|
28
28
|
// std::runtime_error if the file can't be opened for writing.
|
|
29
29
|
void writeDeflateZip(const std::string& path, const std::vector<ZipEntry>& entries);
|
|
30
30
|
|
|
31
|
+
// Compresses `data` to a zlib stream (RFC 1950: 2-byte header, DEFLATE
|
|
32
|
+
// data, Adler-32 trailer) -- which is exactly what PDF's /FlateDecode
|
|
33
|
+
// filter reads, so the PDF writer uses this rather than growing its own
|
|
34
|
+
// compressor. Same stb_image_write.h implementation the ZIP writer above
|
|
35
|
+
// deflates with, only without the wrapper stripped off. Empty if
|
|
36
|
+
// compression fails; the caller can always write the data uncompressed.
|
|
37
|
+
std::vector<uint8_t> zlibCompress(const uint8_t* data, size_t size);
|
|
38
|
+
|
|
31
39
|
// Reads one entry (by exact name match) from a ZIP archive via its central
|
|
32
40
|
// directory (authoritative regardless of how local headers were written).
|
|
33
41
|
// Supports both STORED (method 0, this project's own writeStoredZip()
|
|
@@ -295,7 +295,7 @@ def export_model(path: str, geometry, format: str = "", ascii_stl: bool = False,
|
|
|
295
295
|
strip_slivers: bool = True, split_components: bool = False,
|
|
296
296
|
svg_fill: bool = False, svg_fill_color: str = "white",
|
|
297
297
|
svg_stroke: bool = True, svg_stroke_color: str = "black",
|
|
298
|
-
svg_stroke_width: float = 0.35) -> list:
|
|
298
|
+
svg_stroke_width: float = 0.35, pdf_options: dict | None = None) -> list:
|
|
299
299
|
"""Write `geometry` to `path`. Returns the warnings to surface.
|
|
300
300
|
|
|
301
301
|
`geometry` is the handle an Evaluator stashes on itself as
|
|
@@ -321,11 +321,23 @@ def export_model(path: str, geometry, format: str = "", ascii_stl: bool = False,
|
|
|
321
321
|
`svg_stroke`/`svg_stroke_width` also pad the page, so they are not
|
|
322
322
|
purely cosmetic. An `.svg` export of anything 3D raises, as OpenSCAD's
|
|
323
323
|
does -- there is no projection to fall back on.
|
|
324
|
+
|
|
325
|
+
`pdf_options` is a dict keyed the way OpenSCAD names its own
|
|
326
|
+
`-O export-pdf/...` settings: `paper-size`, `orientation`,
|
|
327
|
+
`show-scale`, `show-scale-message`, `show-grid`, `grid-size`,
|
|
328
|
+
`show-filename`, `design-filename`, `fill`, `fill-color`, `stroke`,
|
|
329
|
+
`stroke-color`, `stroke-width`, `add-meta-data`, `title`, `author`,
|
|
330
|
+
`subject`, `keywords`. An unknown key raises rather than being
|
|
331
|
+
ignored -- a silently dropped `paper-size` would print the wrong page
|
|
332
|
+
size with nothing to explain it. `.pdf` is 2D-only like `.svg`, and
|
|
333
|
+
centres the drawing on a fixed paper size instead of cutting the page
|
|
334
|
+
to fit.
|
|
324
335
|
"""
|
|
325
336
|
try:
|
|
326
337
|
return list(_ext.export_model(path, geometry, format, ascii_stl, strip_slivers,
|
|
327
338
|
split_components, svg_fill, svg_fill_color,
|
|
328
|
-
svg_stroke, svg_stroke_color, svg_stroke_width
|
|
339
|
+
svg_stroke, svg_stroke_color, svg_stroke_width,
|
|
340
|
+
pdf_options))
|
|
329
341
|
except Exception as e:
|
|
330
342
|
raise EvalError(str(e)) from e
|
|
331
343
|
|
|
@@ -201,6 +201,57 @@ void attachTriColors(Evaluator& ev, ColoredBody& cb) {
|
|
|
201
201
|
cb.triColors = std::move(triColors);
|
|
202
202
|
}
|
|
203
203
|
|
|
204
|
+
// One colour's worth of 2D result.
|
|
205
|
+
//
|
|
206
|
+
// 3D recovers per-child colour AFTER the merge, from Manifold's own
|
|
207
|
+
// per-triangle provenance (attachTriColors above). A CrossSection has no
|
|
208
|
+
// such thing -- it is contours, not a mesh, and nothing in it remembers
|
|
209
|
+
// which child a given edge came from. So 2D has to keep colour
|
|
210
|
+
// GEOMETRICALLY instead: one part per colour, each notched by whatever is
|
|
211
|
+
// drawn over it later. That is the same painter's-order rule
|
|
212
|
+
// splitBodiesForExport applies to overlapping 3D solids, and it is what
|
|
213
|
+
// `union() { color("red") square(10); color("blue") ... }` needs to come
|
|
214
|
+
// out as two coloured shapes instead of one shape wearing the first
|
|
215
|
+
// child's colour.
|
|
216
|
+
struct Part2d {
|
|
217
|
+
std::optional<std::array<float, 4>> color;
|
|
218
|
+
manifold::CrossSection section;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// Appends `add` to `parts`, merging into an existing part of the same
|
|
222
|
+
// colour so `union() { color("red") a; color("red") b; }` stays one body.
|
|
223
|
+
void addPart(std::vector<Part2d>& parts, const std::optional<std::array<float, 4>>& color,
|
|
224
|
+
const manifold::CrossSection& section) {
|
|
225
|
+
for (Part2d& p : parts) {
|
|
226
|
+
if (p.color == color) {
|
|
227
|
+
p.section = p.section + section;
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
parts.push_back({color, section});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// The 2D operands of one statement, grouped by colour.
|
|
235
|
+
std::vector<Part2d> partsOf(const std::vector<ColoredBody>& sections2d) {
|
|
236
|
+
std::vector<Part2d> parts;
|
|
237
|
+
for (const ColoredBody& c : sections2d) addPart(parts, c.color, *c.section);
|
|
238
|
+
return parts;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Every part's section unioned -- the shape the statement covers,
|
|
242
|
+
// whatever colours it is in.
|
|
243
|
+
manifold::CrossSection coveredBy(const std::vector<Part2d>& parts) {
|
|
244
|
+
manifold::CrossSection all;
|
|
245
|
+
for (const Part2d& p : parts) all = all + p.section;
|
|
246
|
+
return all;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
void dropEmptyParts(std::vector<Part2d>& parts) {
|
|
250
|
+
parts.erase(std::remove_if(parts.begin(), parts.end(),
|
|
251
|
+
[](const Part2d& p) { return p.section.IsEmpty(); }),
|
|
252
|
+
parts.end());
|
|
253
|
+
}
|
|
254
|
+
|
|
204
255
|
} // namespace
|
|
205
256
|
|
|
206
257
|
std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, const std::vector<std::unique_ptr<CSGNode>>& children,
|
|
@@ -222,7 +273,12 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
222
273
|
// part-way. difference and intersection still see one dimension only:
|
|
223
274
|
// applyDimensionRules drops the mismatch before it gets here, so for
|
|
224
275
|
// them just one of these is ever populated.
|
|
225
|
-
std::optional<ColoredBody> res3d
|
|
276
|
+
std::optional<ColoredBody> res3d;
|
|
277
|
+
// 2D keeps one entry per colour rather than one merged section; see
|
|
278
|
+
// Part2d. `have2d` distinguishes "no 2D operand yet" from "every 2D
|
|
279
|
+
// part has been cut away", which matters to difference().
|
|
280
|
+
std::vector<Part2d> res2d;
|
|
281
|
+
bool have2d = false;
|
|
226
282
|
size_t idx = 0;
|
|
227
283
|
|
|
228
284
|
size_t stmtIndex = 0;
|
|
@@ -282,10 +338,11 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
282
338
|
// union just skips the empty contributor and keeps going.
|
|
283
339
|
if (op == "intersection") {
|
|
284
340
|
res3d.reset();
|
|
285
|
-
res2d.
|
|
341
|
+
res2d.clear();
|
|
342
|
+
have2d = false;
|
|
286
343
|
break;
|
|
287
344
|
}
|
|
288
|
-
if (op == "difference" && !res3d && !
|
|
345
|
+
if (op == "difference" && !res3d && !have2d) break;
|
|
289
346
|
continue;
|
|
290
347
|
}
|
|
291
348
|
|
|
@@ -309,20 +366,25 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
309
366
|
}
|
|
310
367
|
}
|
|
311
368
|
if (!sections2d.empty()) {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
if (!
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
cb.color = sections2d.front().color;
|
|
318
|
-
res2d = std::move(cb);
|
|
369
|
+
std::vector<Part2d> stmtParts = partsOf(sections2d);
|
|
370
|
+
const manifold::CrossSection grp = coveredBy(stmtParts);
|
|
371
|
+
if (!have2d) {
|
|
372
|
+
res2d = std::move(stmtParts);
|
|
373
|
+
have2d = true;
|
|
319
374
|
} else if (op == "union") {
|
|
320
|
-
|
|
375
|
+
// Later wins the overlap: notch what is already there by
|
|
376
|
+
// everything this statement covers, then add this
|
|
377
|
+
// statement's parts. Same rule as two overlapping 3D
|
|
378
|
+
// solids of different colours, and the same thing a
|
|
379
|
+
// painter does.
|
|
380
|
+
for (Part2d& p : res2d) p.section = p.section - grp;
|
|
381
|
+
for (Part2d& np : stmtParts) addPart(res2d, np.color, np.section);
|
|
321
382
|
} else if (op == "difference") {
|
|
322
|
-
res2d
|
|
383
|
+
for (Part2d& p : res2d) p.section = p.section - grp;
|
|
323
384
|
} else if (op == "intersection") {
|
|
324
|
-
res2d
|
|
385
|
+
for (Part2d& p : res2d) p.section = p.section ^ grp;
|
|
325
386
|
}
|
|
387
|
+
dropEmptyParts(res2d);
|
|
326
388
|
}
|
|
327
389
|
}
|
|
328
390
|
|
|
@@ -330,7 +392,12 @@ std::vector<ColoredBody> generateCsg(Evaluator& ev, const CSGParams& params, con
|
|
|
330
392
|
|
|
331
393
|
std::vector<ColoredBody> result;
|
|
332
394
|
if (res3d) result.push_back(std::move(*res3d));
|
|
333
|
-
|
|
395
|
+
for (Part2d& p : res2d) {
|
|
396
|
+
ColoredBody cb;
|
|
397
|
+
cb.color = p.color;
|
|
398
|
+
cb.section = std::move(p.section);
|
|
399
|
+
result.push_back(std::move(cb));
|
|
400
|
+
}
|
|
334
401
|
result.insert(result.end(), allBg.begin(), allBg.end());
|
|
335
402
|
result.insert(result.end(), allHi.begin(), allHi.end());
|
|
336
403
|
result.insert(result.end(), allSo.begin(), allSo.end());
|