openscad-cpp-evaluator 1.31.0__tar.gz → 1.33.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.31.0 → openscad_cpp_evaluator-1.33.0}/.github/workflows/wheels.yml +9 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/CLAUDE.md +26 -2
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/PKG-INFO +1 -1
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/bindings/module.cpp +22 -3
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/export.hpp +41 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/pyproject.toml +1 -1
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/python/openscad_cpp_evaluator/__init__.py +8 -2
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/export.cpp +266 -3
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_export.cpp +243 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_python_bindings.py +121 -26
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/uv.lock +1 -1
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/.gitignore +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/.gitmodules +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/LICENSE +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/README.md +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/bindings/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/bindings/ast_to_py.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/cmake/embed_font.cmake +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/examples/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/examples/eval_perf_benchmark.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/examples/manifold_cache_reuse.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/examples/minimal_debugger.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/.gitignore +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/README.md +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/.DS_Store +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/resources/fonts/LICENSE +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/builtins.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/call_args.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/color.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/control.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/dxf_dim.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/extrude.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/import.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/modifiers.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/primitives_2d.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/primitives_3d.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/registry.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/roof.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/segments.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/surface.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/text.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/topology.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/builtins/transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/bytecode_vm.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/colored_body.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/csg_generate.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/csg_resolve.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/css_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/debug/debug_repl.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/debug_profile.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/eval_error.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/eval_use.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/format_closure.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/import/dxf_import.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/import/mesh_import.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/import/surface_load.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/import/svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/measure_geometry.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/stmt_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/text/font_match.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/text/freetype_font_provider.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/text/text_metrics.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/user_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/utf8.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/value.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/xkcd_colors.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/xkcd_colors.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/src/zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_booleans.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_bytecode_compiler.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_children_separate.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_cli.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_control_flow.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_coverage.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_csg_tree.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_debug_hooks.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_discretizer.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_dxf_svg_import.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_eval_context.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_expr_eval.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_extrude_roof.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_feature_detection.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_function_builtins.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_helpers.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_import_export.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_include_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_manifold_cache.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_mesh_check.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_multi_color_merge.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_primitives.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_profiling.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_render_expr.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_scope_trail.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_scoping.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_surface.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_tail_calls.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_text.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_transforms.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_unexpected_args.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_use.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_value.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_viewport_params.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tests/test_zip_stored.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tools/cli/CMakeLists.txt +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tools/cli/cli_lib.cpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tools/cli/cli_lib.hpp +0 -0
- {openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/tools/cli/main.cpp +0 -0
{openscad_cpp_evaluator-1.31.0 → openscad_cpp_evaluator-1.33.0}/.github/workflows/wheels.yml
RENAMED
|
@@ -119,6 +119,9 @@ jobs:
|
|
|
119
119
|
# C:\msys64 (not on PATH); its bison/flex satisfy the parser
|
|
120
120
|
# submodule's grammar version requirement.
|
|
121
121
|
CIBW_BEFORE_ALL_WINDOWS: 'C:\msys64\usr\bin\bash.exe -lc "pacman -Sy --noconfirm bison flex"'
|
|
122
|
+
# The binding tests run under pytest (the file's own entry point
|
|
123
|
+
# hands over to it): most of them take tmp_path or use pytest.raises.
|
|
124
|
+
CIBW_TEST_REQUIRES: "pytest"
|
|
122
125
|
CIBW_TEST_COMMAND: "python {package}/tests/test_python_bindings.py"
|
|
123
126
|
|
|
124
127
|
- uses: actions/upload-artifact@v7
|
|
@@ -128,6 +131,9 @@ jobs:
|
|
|
128
131
|
|
|
129
132
|
publish-testpypi:
|
|
130
133
|
needs: [sdist, build_wheels]
|
|
134
|
+
# Tags only: a manual dispatch builds and tests every wheel, and must
|
|
135
|
+
# never publish whatever branch it was run on.
|
|
136
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
131
137
|
runs-on: ubuntu-latest
|
|
132
138
|
environment: testpypi
|
|
133
139
|
steps:
|
|
@@ -164,6 +170,9 @@ jobs:
|
|
|
164
170
|
|
|
165
171
|
publish-pypi:
|
|
166
172
|
needs: [publish-testpypi]
|
|
173
|
+
# Tags only: a manual dispatch builds and tests every wheel, and must
|
|
174
|
+
# never publish whatever branch it was run on.
|
|
175
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
167
176
|
runs-on: ubuntu-latest
|
|
168
177
|
# The "pypi" environment carries no protection rules, so a tag runs
|
|
169
178
|
# straight through TestPyPI to PyPI with nothing to stop it -- and a
|
|
@@ -1091,8 +1091,8 @@ grep for `ponytail:`.
|
|
|
1091
1091
|
— skip it and the mesh comes out non-manifold at the seam). Self-contained 2D geometry math here
|
|
1092
1092
|
(`dot2`/`len2`/`norm2`, the parabola-canonical-frame rotation in `discretizeArc`) exists nowhere
|
|
1093
1093
|
else in this codebase.
|
|
1094
|
-
- `include/openscad_cpp_evaluator/export.hpp`, `src/export.cpp` — the writers for all
|
|
1095
|
-
formats `exportExtensions()` lists: 3MF, AMF, PDF, STL, OBJ, OFF, PLY, SVG, VRML, X3D (3MF via
|
|
1094
|
+
- `include/openscad_cpp_evaluator/export.hpp`, `src/export.cpp` — the writers for all twelve
|
|
1095
|
+
formats `exportExtensions()` lists: 3MF, AMF, DXF, PDF, STL, OBJ, OFF, PLY, POV, SVG, VRML, X3D (3MF via
|
|
1096
1096
|
`zip_stored.hpp`'s `writeDeflateZip`). **`exportExtensions()` is the one source of truth for
|
|
1097
1097
|
which formats exist** — the Python facade and BelfrySCAD's dialog/CLI all ask it rather than
|
|
1098
1098
|
restating the list, because three hand-written copies had already drifted far enough that `.off`
|
|
@@ -1120,6 +1120,30 @@ grep for `ponytail:`.
|
|
|
1120
1120
|
binary's, vertex order and 6-vertex line wrap included. A 3D body in the list throws
|
|
1121
1121
|
("Current top level object is not a 2D object"), as OpenSCAD refuses too: there is no projection
|
|
1122
1122
|
to fall back on. `ExportOptions::svg` carries OpenSCAD's five `-O export-svg/...` settings.
|
|
1123
|
+
**`writePov` writes POV-Ray, as `mesh2`** — one per object `splitBodiesForExport` produces, with
|
|
1124
|
+
a welded vertex list, a `texture_list` of the object's colours and a texture index per triangle
|
|
1125
|
+
(so per-triangle colour needs no unwelding, unlike PLY), and `inside_vector` so POV-Ray treats it
|
|
1126
|
+
as a SOLID (the `ior 1.32` interior refracts; CSG works). OpenSCAD's `export_pov.cc` writes every
|
|
1127
|
+
face as its own flat `polygon` object instead. The rest of the scene is OpenSCAD's: header,
|
|
1128
|
+
MATERIAL finish, 27 lights around the bounding box, radiosity from `rad_def.inc`, colour as
|
|
1129
|
+
`rgbf` with filter = 1 − alpha. `ExportPovOptions::camera` ($vpt, $vpr, distance, fov; Python
|
|
1130
|
+
`pov_camera`, 8 numbers) writes OpenSCAD's camera block with **two fixes, both found by rendering
|
|
1131
|
+
in POV-Ray 3.7 and comparing with BelfrySCAD's PNG of the same camera** (they now agree to a
|
|
1132
|
+
pixel): `rotate` comes before `translate`, since the eye orbits `$vpt` (OpenSCAD translates first
|
|
1133
|
+
and frames the wrong place when a view both pans and turns); and the viewport's **vertical** fov
|
|
1134
|
+
becomes POV-Ray's **horizontal** `angle` through an expression on `image_width/image_height`
|
|
1135
|
+
(OpenSCAD writes it across unchanged, zooming its renders in by the aspect ratio). No camera frames
|
|
1136
|
+
the bounding box, as OpenSCAD does without one.
|
|
1137
|
+
**`writeDxf` is the third 2D writer**, also on `collect2d()`: OpenSCAD's own `export_dxf.cc`
|
|
1138
|
+
layout verbatim (AC1006 header with the extents, one CONTINUOUS linetype, layer 0, every contour
|
|
1139
|
+
a closed `LWPOLYLINE` on layer 0 with holes as ordinary contours; 1- and 2-vertex contours as
|
|
1140
|
+
`POINT`/`LINE`), pinned byte-for-byte by `ExportDxf.MatchesRealOpenscadByteForByte`. Two
|
|
1141
|
+
deliberate differences: coordinates are the **shortest text that round-trips the double**
|
|
1142
|
+
(`dxfNum`), not OpenSCAD's 6 significant digits -- a DXF feeds a cutter, and its circles do not
|
|
1143
|
+
survive a re-import otherwise; and `$EXTMAX` is right for a model below zero (OpenSCAD seeds its
|
|
1144
|
+
maxima with `numeric_limits<double>::min()`, the smallest POSITIVE double). Every number goes
|
|
1145
|
+
through the classic locale, the file stream included: Qt sets the process locale, and a grouping
|
|
1146
|
+
locale writes a 1500-vertex count as `1.500`.
|
|
1123
1147
|
**`writePdf` is the other 2D writer**, and shares `collect2d()` with `writeSvg` so the all-2D
|
|
1124
1148
|
rule and its refusal have one implementation. Everything else differs from SVG: the drawing is
|
|
1125
1149
|
**centred on a fixed paper size** rather than the page being cut to fit, and **PDF user space is
|
|
@@ -436,14 +436,30 @@ nb::list exportModelPy(const std::string& path, const Geometry& geom, const std:
|
|
|
436
436
|
bool stripSlivers, bool splitComponents, bool splitColors, bool svgFill,
|
|
437
437
|
const std::string& svgFillColor,
|
|
438
438
|
bool svgStroke, const std::string& svgStrokeColor, double svgStrokeWidth,
|
|
439
|
-
nb::object pdfOptions) {
|
|
439
|
+
nb::object pdfOptions, nb::object povCamera) {
|
|
440
440
|
oscadeval::ExportPdfOptions pdf;
|
|
441
441
|
if (!pdfOptions.is_none()) applyPdfOptions(nb::cast<nb::dict>(pdfOptions), pdf);
|
|
442
|
+
oscadeval::ExportPovOptions pov;
|
|
443
|
+
if (!povCamera.is_none()) {
|
|
444
|
+
const std::vector<double> c = nb::cast<std::vector<double>>(povCamera);
|
|
445
|
+
if (c.size() != 8) {
|
|
446
|
+
throw std::runtime_error("pov_camera takes 8 numbers: $vpt x, y, z, $vpr x, y, z, distance, fov");
|
|
447
|
+
}
|
|
448
|
+
oscadeval::ExportPovCamera cam;
|
|
449
|
+
for (int k = 0; k < 3; ++k) {
|
|
450
|
+
cam.vpt[k] = c[k];
|
|
451
|
+
cam.vpr[k] = c[3 + k];
|
|
452
|
+
}
|
|
453
|
+
cam.distance = c[6];
|
|
454
|
+
cam.fov = c[7];
|
|
455
|
+
pov.camera = cam;
|
|
456
|
+
}
|
|
442
457
|
std::vector<std::string> warnings;
|
|
443
458
|
{
|
|
444
459
|
nb::gil_scoped_release rel;
|
|
445
460
|
oscadeval::ExportOptions opts;
|
|
446
461
|
opts.pdf = pdf;
|
|
462
|
+
opts.pov = pov;
|
|
447
463
|
opts.format = format;
|
|
448
464
|
opts.asciiStl = asciiStl;
|
|
449
465
|
opts.stripSlivers = stripSlivers;
|
|
@@ -957,7 +973,7 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
957
973
|
nb::arg("svg_fill") = false,
|
|
958
974
|
nb::arg("svg_fill_color") = std::string("white"), nb::arg("svg_stroke") = true,
|
|
959
975
|
nb::arg("svg_stroke_color") = std::string("black"), nb::arg("svg_stroke_width") = 0.35,
|
|
960
|
-
nb::arg("pdf_options") = nb::none(),
|
|
976
|
+
nb::arg("pdf_options") = nb::none(), nb::arg("pov_camera") = nb::none(),
|
|
961
977
|
"Write `geometry` to `path`, format taken from the extension unless `format` says otherwise. "
|
|
962
978
|
"Returns the warnings to surface (open shells, mesh problems, slivers removed) rather than "
|
|
963
979
|
"logging them. Raises RuntimeError when there is no geometry, the format is unknown, or the "
|
|
@@ -976,7 +992,10 @@ NB_MODULE(_openscad_cpp_evaluator, m) {
|
|
|
976
992
|
"(paper-size, orientation, show-scale, show-scale-message, show-grid, grid-size, "
|
|
977
993
|
"show-filename, design-filename, fill, fill-color, stroke, stroke-color, stroke-width, "
|
|
978
994
|
"add-meta-data, title, author, subject, keywords). An unknown key raises rather than "
|
|
979
|
-
"being ignored. .pdf is 2D-only too, and centres the drawing on a fixed paper size
|
|
995
|
+
"being ignored. .pdf is 2D-only too, and centres the drawing on a fixed paper size.\n\n"
|
|
996
|
+
"pov_camera is .pov's camera as 8 numbers -- $vpt x, y, z, $vpr x, y, z, distance, fov -- "
|
|
997
|
+
"so a POV-Ray render frames what the viewport showed. None frames the model from its "
|
|
998
|
+
"bounding box, as OpenSCAD does without a camera.");
|
|
980
999
|
|
|
981
1000
|
m.def("list_fonts", []() {
|
|
982
1001
|
nb::list out;
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
#include <array>
|
|
6
6
|
#include <cstdint>
|
|
7
|
+
#include <optional>
|
|
7
8
|
#include <string>
|
|
8
9
|
#include <vector>
|
|
9
10
|
|
|
@@ -158,6 +159,17 @@ struct ExportSvgOptions {
|
|
|
158
159
|
void writeSvg(const std::string& path, const std::vector<ColoredBody>& bodies,
|
|
159
160
|
const ExportSvgOptions& opts = {});
|
|
160
161
|
|
|
162
|
+
// DXF, the third 2D writer: OpenSCAD's own export_dxf.cc layout (an AC1006
|
|
163
|
+
// header with the model's extents, one CONTINUOUS linetype, layer 0) and
|
|
164
|
+
// every contour of every body a closed LWPOLYLINE on layer 0 -- holes are
|
|
165
|
+
// contours like any other, as in OpenSCAD. A 1-vertex contour is a POINT
|
|
166
|
+
// and a 2-vertex one a LINE, again as OpenSCAD writes them. Shares
|
|
167
|
+
// collect2d() with writeSvg/writePdf, so a 3D model is refused the same
|
|
168
|
+
// way. Coordinates are written at full round-trip precision, NOT OpenSCAD's
|
|
169
|
+
// 6 significant digits: a DXF goes to a cutter, where 1234.567 written as
|
|
170
|
+
// 1234.57 is a real error.
|
|
171
|
+
void writeDxf(const std::string& path, const std::vector<ColoredBody>& bodies);
|
|
172
|
+
|
|
161
173
|
// Options for the PDF writer, named and defaulted after OpenSCAD's own
|
|
162
174
|
// `-O export-pdf/...` set.
|
|
163
175
|
struct ExportPdfOptions {
|
|
@@ -222,6 +234,33 @@ std::vector<std::string> writePdf(const std::string& path, const std::vector<Col
|
|
|
222
234
|
|
|
223
235
|
// -- one entry point ------------------------------------------------------
|
|
224
236
|
|
|
237
|
+
// POV-Ray's camera, as OpenSCAD's viewport states it: $vpt, $vpr, $vpd and
|
|
238
|
+
// the field of view. Without one the scene is framed from the model's
|
|
239
|
+
// bounding box, as OpenSCAD frames it when it has no camera to pass.
|
|
240
|
+
struct ExportPovCamera {
|
|
241
|
+
double vpt[3] = {0, 0, 0};
|
|
242
|
+
double vpr[3] = {0, 0, 0};
|
|
243
|
+
double distance = 0;
|
|
244
|
+
double fov = 22.5;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
struct ExportPovOptions {
|
|
248
|
+
std::optional<ExportPovCamera> camera;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// POV-Ray scene description. Every object splitBodiesForExport produces is
|
|
252
|
+
// one mesh2 -- a welded vertex list, a texture per colour, and a texture
|
|
253
|
+
// index per triangle, so per-triangle colour needs no unwelding -- with
|
|
254
|
+
// inside_vector, which makes it a SOLID to POV-Ray (refraction, CSG). That
|
|
255
|
+
// is the difference from OpenSCAD's export_pov.cc, which writes every face
|
|
256
|
+
// as its own flat polygon object. The rest of the scene is OpenSCAD's: its
|
|
257
|
+
// header, MATERIAL finish and ior 1.32 interior, 27 lights around the
|
|
258
|
+
// bounding box, its camera, and radiosity from rad_def.inc. Colour is rgbf
|
|
259
|
+
// with filter = 1 - alpha, as OpenSCAD writes it. Numbers are the shortest
|
|
260
|
+
// text that round-trips, in the classic locale.
|
|
261
|
+
void writePov(const std::string& path, const std::vector<ExportObject>& objects,
|
|
262
|
+
const ExportPovOptions& opts = {});
|
|
263
|
+
|
|
225
264
|
struct ExportOptions {
|
|
226
265
|
// Empty means "decide from the path's extension".
|
|
227
266
|
std::string format;
|
|
@@ -247,6 +286,8 @@ struct ExportOptions {
|
|
|
247
286
|
ExportSvgOptions svg;
|
|
248
287
|
// .pdf only.
|
|
249
288
|
ExportPdfOptions pdf;
|
|
289
|
+
// .pov only.
|
|
290
|
+
ExportPovOptions pov;
|
|
250
291
|
};
|
|
251
292
|
|
|
252
293
|
// Writes `bodies` to `path`, choosing the writer from the extension (or
|
|
@@ -331,7 +331,8 @@ def export_model(path: str, geometry, format: str = "", ascii_stl: bool = False,
|
|
|
331
331
|
split_colors: bool = True,
|
|
332
332
|
svg_fill: bool = False, svg_fill_color: str = "white",
|
|
333
333
|
svg_stroke: bool = True, svg_stroke_color: str = "black",
|
|
334
|
-
svg_stroke_width: float = 0.35, pdf_options: dict | None = None
|
|
334
|
+
svg_stroke_width: float = 0.35, pdf_options: dict | None = None,
|
|
335
|
+
pov_camera=None) -> list:
|
|
335
336
|
"""Write `geometry` to `path`. Returns the warnings to surface.
|
|
336
337
|
|
|
337
338
|
`geometry` is the handle an Evaluator stashes on itself as
|
|
@@ -374,12 +375,17 @@ def export_model(path: str, geometry, format: str = "", ascii_stl: bool = False,
|
|
|
374
375
|
size with nothing to explain it. `.pdf` is 2D-only like `.svg`, and
|
|
375
376
|
centres the drawing on a fixed paper size instead of cutting the page
|
|
376
377
|
to fit.
|
|
378
|
+
|
|
379
|
+
`pov_camera` is `.pov`'s camera as eight numbers -- `$vpt` x, y, z,
|
|
380
|
+
`$vpr` x, y, z, distance, field of view -- so a POV-Ray render frames
|
|
381
|
+
what the viewport showed. None frames the model from its bounding box,
|
|
382
|
+
as OpenSCAD does when it has no camera to pass.
|
|
377
383
|
"""
|
|
378
384
|
try:
|
|
379
385
|
return list(_ext.export_model(path, geometry, format, ascii_stl, strip_slivers,
|
|
380
386
|
split_components, split_colors, svg_fill, svg_fill_color,
|
|
381
387
|
svg_stroke, svg_stroke_color, svg_stroke_width,
|
|
382
|
-
pdf_options))
|
|
388
|
+
pdf_options, pov_camera))
|
|
383
389
|
except Exception as e:
|
|
384
390
|
raise EvalError(str(e)) from e
|
|
385
391
|
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
#include <cstdio>
|
|
14
14
|
#include <ctime>
|
|
15
15
|
#include <fstream>
|
|
16
|
+
#include <locale>
|
|
17
|
+
#include <sstream>
|
|
16
18
|
#include <optional>
|
|
17
19
|
#include <stdexcept>
|
|
18
20
|
|
|
@@ -913,7 +915,8 @@ std::string lowerExtension(const std::string& path) {
|
|
|
913
915
|
}
|
|
914
916
|
|
|
915
917
|
bool isMultiObject(const std::string& ext) {
|
|
916
|
-
return ext == ".3mf" || ext == ".amf" || ext == ".obj" || ext == ".ply" || ext == ".
|
|
918
|
+
return ext == ".3mf" || ext == ".amf" || ext == ".obj" || ext == ".ply" || ext == ".pov" || ext == ".wrl" ||
|
|
919
|
+
ext == ".x3d";
|
|
917
920
|
}
|
|
918
921
|
|
|
919
922
|
// The merged single mesh STL/OFF write, with the open shells kept.
|
|
@@ -1155,6 +1158,258 @@ void writeSvg(const std::string& path, const std::vector<ColoredBody>& bodies, c
|
|
|
1155
1158
|
|
|
1156
1159
|
namespace {
|
|
1157
1160
|
|
|
1161
|
+
// The shortest decimal that reads back as exactly `v`, in the classic
|
|
1162
|
+
// locale (Qt sets the process locale from the environment, so printf could
|
|
1163
|
+
// write "1,5" on a German system and no DXF reader would take it). -0 is
|
|
1164
|
+
// written as 0, and a non-finite value -- which no contour should hold --
|
|
1165
|
+
// as 0 rather than as text a reader would choke on.
|
|
1166
|
+
std::string dxfNum(double v) {
|
|
1167
|
+
if (!std::isfinite(v) || v == 0.0) return "0";
|
|
1168
|
+
for (int digits = 6; digits <= 17; ++digits) {
|
|
1169
|
+
std::ostringstream o;
|
|
1170
|
+
o.imbue(std::locale::classic());
|
|
1171
|
+
o.precision(digits);
|
|
1172
|
+
o << v;
|
|
1173
|
+
std::istringstream in(o.str());
|
|
1174
|
+
in.imbue(std::locale::classic());
|
|
1175
|
+
double back = 0.0;
|
|
1176
|
+
in >> back;
|
|
1177
|
+
if (back == v) return o.str();
|
|
1178
|
+
}
|
|
1179
|
+
std::ostringstream o; // unreachable: 17 digits always round-trips a double
|
|
1180
|
+
o.imbue(std::locale::classic());
|
|
1181
|
+
o.precision(17);
|
|
1182
|
+
o << v;
|
|
1183
|
+
return o.str();
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// The header, tables and (empty) blocks sections, verbatim from OpenSCAD's
|
|
1187
|
+
// export_dxf.cc -- its comments record which readers each piece was needed
|
|
1188
|
+
// for (Inkscape, LibreCAD, Illustrator, sharecad.org, generic cutters).
|
|
1189
|
+
void writeDxfHeader(std::ostream& out, double xMin, double yMin, double xMax, double yMax) {
|
|
1190
|
+
out << "999\nDXF from OpenSCAD\n"
|
|
1191
|
+
<< " 0\nSECTION\n 2\nHEADER\n"
|
|
1192
|
+
<< " 9\n$ACADVER\n 1\nAC1006\n"
|
|
1193
|
+
<< " 9\n$INSBASE\n 10\n0.0\n 20\n0.0\n 30\n0.0\n";
|
|
1194
|
+
for (const char* name : {"$EXTMIN", "$EXTMAX", "$LINMIN", "$LINMAX"}) {
|
|
1195
|
+
const bool isMin = std::string(name).find("MIN") != std::string::npos;
|
|
1196
|
+
out << " 9\n" << name << "\n 10\n" << dxfNum(isMin ? xMin : xMax) << "\n 20\n"
|
|
1197
|
+
<< dxfNum(isMin ? yMin : yMax) << "\n";
|
|
1198
|
+
}
|
|
1199
|
+
out << " 0\nENDSEC\n"
|
|
1200
|
+
<< " 0\nSECTION\n 2\nTABLES\n"
|
|
1201
|
+
<< " 0\nTABLE\n 2\nLTYPE\n 70\n1\n"
|
|
1202
|
+
<< " 0\nLTYPE\n 2\nCONTINUOUS\n 70\n64\n 3\nSolid line\n 72\n65\n 73\n0\n 40\n0.000000\n"
|
|
1203
|
+
<< " 0\nENDTAB\n"
|
|
1204
|
+
<< " 0\nTABLE\n 2\nLAYER\n 70\n6\n"
|
|
1205
|
+
<< " 0\nLAYER\n 2\n0\n 70\n64\n 62\n7\n 6\nCONTINUOUS\n"
|
|
1206
|
+
<< " 0\nENDTAB\n"
|
|
1207
|
+
<< " 0\nTABLE\n 2\nSTYLE\n 70\n0\n 0\nENDTAB\n"
|
|
1208
|
+
<< " 0\nENDSEC\n"
|
|
1209
|
+
<< " 0\nSECTION\n 2\nBLOCKS\n 0\nENDSEC\n";
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
} // namespace
|
|
1213
|
+
|
|
1214
|
+
void writeDxf(const std::string& path, const std::vector<ColoredBody>& bodies) {
|
|
1215
|
+
const Flat2d flat = collect2d(bodies);
|
|
1216
|
+
|
|
1217
|
+
std::ofstream out(path);
|
|
1218
|
+
if (!out) throw std::runtime_error("Could not open '" + path + "' for writing");
|
|
1219
|
+
// The vertex counts go through the stream itself, which otherwise takes
|
|
1220
|
+
// the global C++ locale -- one with digit grouping writes 1500 as "1.500".
|
|
1221
|
+
out.imbue(std::locale::classic());
|
|
1222
|
+
|
|
1223
|
+
// Extents from collect2d's own bounding box. OpenSCAD starts its maxima
|
|
1224
|
+
// at numeric_limits<double>::min() -- the smallest POSITIVE double, not
|
|
1225
|
+
// the most negative -- so a model lying entirely at negative x or y gets
|
|
1226
|
+
// a wrong $EXTMAX there. That is a bug, not a format rule.
|
|
1227
|
+
writeDxfHeader(out, flat.minx, flat.miny, flat.maxx, flat.maxy);
|
|
1228
|
+
|
|
1229
|
+
out << " 0\nSECTION\n 2\nENTITIES\n";
|
|
1230
|
+
for (const manifold::Polygons& polys : flat.perBody) {
|
|
1231
|
+
for (const manifold::SimplePolygon& contour : polys) {
|
|
1232
|
+
const auto xy = [&](const char* xCode, const char* yCode, const manifold::vec2& p) {
|
|
1233
|
+
out << xCode << "\n" << dxfNum(p.x) << "\n" << yCode << "\n" << dxfNum(p.y) << "\n";
|
|
1234
|
+
};
|
|
1235
|
+
switch (contour.size()) {
|
|
1236
|
+
case 0:
|
|
1237
|
+
break;
|
|
1238
|
+
case 1:
|
|
1239
|
+
out << " 0\nPOINT\n100\nAcDbEntity\n 8\n0\n100\nAcDbPoint\n";
|
|
1240
|
+
xy(" 10", " 20", contour[0]);
|
|
1241
|
+
break;
|
|
1242
|
+
case 2:
|
|
1243
|
+
// [X1 Y1 X2 Y2]: the order ezdxf and dxfgrabber can read.
|
|
1244
|
+
out << " 0\nLINE\n100\nAcDbEntity\n 8\n0\n100\nAcDbLine\n";
|
|
1245
|
+
xy(" 10", " 20", contour[0]);
|
|
1246
|
+
xy(" 11", " 21", contour[1]);
|
|
1247
|
+
break;
|
|
1248
|
+
default:
|
|
1249
|
+
out << " 0\nLWPOLYLINE\n100\nAcDbEntity\n 8\n0\n100\nAcDbPolyline\n"
|
|
1250
|
+
<< " 90\n" << contour.size() << "\n 70\n1\n"; // 70 = 1: closed
|
|
1251
|
+
for (const manifold::vec2& p : contour) xy(" 10", " 20", p);
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
out << " 0\nENDSEC\n 0\nEOF\n";
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
namespace {
|
|
1259
|
+
|
|
1260
|
+
// dxfNum's rule for a float: the shortest text that reads back as the same
|
|
1261
|
+
// float. Mesh vertices and colours are floats, and printing them as doubles
|
|
1262
|
+
// would turn 0.1f into 0.100000001490116.
|
|
1263
|
+
std::string floatNum(float v) {
|
|
1264
|
+
if (!std::isfinite(v) || v == 0.0f) return "0";
|
|
1265
|
+
for (int digits = 6; digits <= 9; ++digits) {
|
|
1266
|
+
std::ostringstream o;
|
|
1267
|
+
o.imbue(std::locale::classic());
|
|
1268
|
+
o.precision(digits);
|
|
1269
|
+
o << v;
|
|
1270
|
+
std::istringstream in(o.str());
|
|
1271
|
+
in.imbue(std::locale::classic());
|
|
1272
|
+
float back = 0.0f;
|
|
1273
|
+
in >> back;
|
|
1274
|
+
if (back == v) return o.str();
|
|
1275
|
+
}
|
|
1276
|
+
std::ostringstream o; // unreachable: 9 digits always round-trips a float
|
|
1277
|
+
o.imbue(std::locale::classic());
|
|
1278
|
+
o.precision(9);
|
|
1279
|
+
o << v;
|
|
1280
|
+
return o.str();
|
|
1281
|
+
}
|
|
1282
|
+
|
|
1283
|
+
std::string povVec(double x, double y, double z) {
|
|
1284
|
+
return "<" + dxfNum(x) + ", " + dxfNum(y) + ", " + dxfNum(z) + ">";
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
} // namespace
|
|
1288
|
+
|
|
1289
|
+
void writePov(const std::string& path, const std::vector<ExportObject>& objects, const ExportPovOptions& opts) {
|
|
1290
|
+
std::ofstream out(path);
|
|
1291
|
+
if (!out) throw std::runtime_error("Could not open '" + path + "' for writing");
|
|
1292
|
+
out.imbue(std::locale::classic());
|
|
1293
|
+
|
|
1294
|
+
out << "// Generated by BelfrySCAD (openscad_cpp_evaluator)\n\n"
|
|
1295
|
+
<< "// Camera settings are at the bottom of this script\n\n"
|
|
1296
|
+
<< "#version 3.7;\n"
|
|
1297
|
+
<< "global_settings { assumed_gamma 1.0 }\n"
|
|
1298
|
+
<< "#declare MATERIAL=finish { specular 0.5 roughness 0.001 reflection{0 0.63 fresnel} ambient 0 "
|
|
1299
|
+
"diffuse 0.6 conserve_energy }\n"
|
|
1300
|
+
<< "#declare MATERIAL_INT=interior{ior 1.32}\n";
|
|
1301
|
+
|
|
1302
|
+
const auto rgbf = [](const std::array<float, 4>& c) {
|
|
1303
|
+
return "<" + floatNum(c[0]) + ", " + floatNum(c[1]) + ", " + floatNum(c[2]) + ", " +
|
|
1304
|
+
floatNum(1.0f - c[3]) + ">";
|
|
1305
|
+
};
|
|
1306
|
+
|
|
1307
|
+
bool any = false;
|
|
1308
|
+
double lo[3] = {0, 0, 0}, hi[3] = {0, 0, 0};
|
|
1309
|
+
for (const ExportObject& o : objects) {
|
|
1310
|
+
const size_t vertCount = o.verts.size() / 3;
|
|
1311
|
+
const size_t triCount = o.tris.size() / 3;
|
|
1312
|
+
if (vertCount == 0 || triCount == 0) continue;
|
|
1313
|
+
for (size_t v = 0; v < vertCount; ++v) {
|
|
1314
|
+
for (int k = 0; k < 3; ++k) {
|
|
1315
|
+
const double c = o.verts[v * 3 + k];
|
|
1316
|
+
if (!any) {
|
|
1317
|
+
lo[k] = hi[k] = c;
|
|
1318
|
+
} else {
|
|
1319
|
+
lo[k] = std::min(lo[k], c);
|
|
1320
|
+
hi[k] = std::max(hi[k], c);
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
any = true;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// One texture per distinct colour, in order of first use.
|
|
1327
|
+
std::vector<std::array<float, 4>> palette;
|
|
1328
|
+
std::vector<size_t> triTexture(triCount, 0);
|
|
1329
|
+
const auto textureOf = [&](const std::array<float, 4>& c) {
|
|
1330
|
+
for (size_t i = 0; i < palette.size(); ++i) {
|
|
1331
|
+
if (palette[i] == c) return i;
|
|
1332
|
+
}
|
|
1333
|
+
palette.push_back(c);
|
|
1334
|
+
return palette.size() - 1;
|
|
1335
|
+
};
|
|
1336
|
+
for (size_t t = 0; t < triCount; ++t) {
|
|
1337
|
+
triTexture[t] = textureOf(o.triColors.empty() ? o.color : o.triColors[t]);
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
out << "mesh2 {\n vertex_vectors { " << vertCount;
|
|
1341
|
+
for (size_t v = 0; v < vertCount; ++v) {
|
|
1342
|
+
out << ",\n <" << floatNum(o.verts[v * 3]) << ", " << floatNum(o.verts[v * 3 + 1]) << ", "
|
|
1343
|
+
<< floatNum(o.verts[v * 3 + 2]) << ">";
|
|
1344
|
+
}
|
|
1345
|
+
out << "\n }\n texture_list { " << palette.size();
|
|
1346
|
+
for (const std::array<float, 4>& c : palette) {
|
|
1347
|
+
out << "\n texture { pigment { color rgbf " << rgbf(c) << " } finish { MATERIAL } }";
|
|
1348
|
+
}
|
|
1349
|
+
out << "\n }\n face_indices { " << triCount;
|
|
1350
|
+
for (size_t t = 0; t < triCount; ++t) {
|
|
1351
|
+
out << ",\n <" << o.tris[t * 3] << ", " << o.tris[t * 3 + 1] << ", " << o.tris[t * 3 + 2] << ">, "
|
|
1352
|
+
<< triTexture[t];
|
|
1353
|
+
}
|
|
1354
|
+
// inside_vector: without it POV-Ray treats a mesh as a bare surface,
|
|
1355
|
+
// with no inside for the interior (and its ior) or CSG to act on.
|
|
1356
|
+
out << "\n }\n inside_vector <0, 0, 1>\n interior { MATERIAL_INT }\n}\n";
|
|
1357
|
+
}
|
|
1358
|
+
if (!any) throw std::runtime_error("No geometry to export");
|
|
1359
|
+
|
|
1360
|
+
// 27 lights: every combination of {below, centre, above} on each axis,
|
|
1361
|
+
// twice the model's size out, at OpenSCAD's brightness.
|
|
1362
|
+
const double move = 2.0;
|
|
1363
|
+
double at[3][3];
|
|
1364
|
+
for (int k = 0; k < 3; ++k) {
|
|
1365
|
+
const double d = hi[k] - lo[k];
|
|
1366
|
+
at[k][0] = lo[k] - d * move;
|
|
1367
|
+
at[k][1] = (lo[k] + hi[k]) / 2.0;
|
|
1368
|
+
at[k][2] = hi[k] + d * move;
|
|
1369
|
+
}
|
|
1370
|
+
for (double x : at[0]) {
|
|
1371
|
+
for (double y : at[1]) {
|
|
1372
|
+
for (double z : at[2]) {
|
|
1373
|
+
out << "light_source { " << povVec(x, y, z) << " color rgb <0.2, 0.2, 0.2> }\n";
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
if (opts.camera) {
|
|
1379
|
+
// OpenSCAD's camera block, with two fixes, both checked by rendering
|
|
1380
|
+
// in POV-Ray against BelfrySCAD's own image of the same camera:
|
|
1381
|
+
// - rotate BEFORE translate. The eye orbits $vpt, so it is rotated
|
|
1382
|
+
// about the origin and then moved; OpenSCAD translates first,
|
|
1383
|
+
// which rotates $vpt itself away and frames the wrong place
|
|
1384
|
+
// whenever a view both pans and turns.
|
|
1385
|
+
// - the field of view is VERTICAL in the viewport and HORIZONTAL to
|
|
1386
|
+
// POV-Ray's `angle`. OpenSCAD writes it straight across, so its
|
|
1387
|
+
// renders come out zoomed in by the aspect ratio (1.33x at 4:3).
|
|
1388
|
+
// The horizontal angle is left to POV-Ray to work out from the
|
|
1389
|
+
// image it is asked for, so any size frames the same.
|
|
1390
|
+
const ExportPovCamera& c = *opts.camera;
|
|
1391
|
+
out << "camera { look_at <0, 0, 0>\n"
|
|
1392
|
+
<< " location <0, 0, " << dxfNum(c.distance) << ">\n"
|
|
1393
|
+
<< " angle degrees(2 * atan(tan(radians(" << dxfNum(c.fov) << " / 2)) * image_width / image_height))"
|
|
1394
|
+
<< " up <0, 1, 0> right <1, 0, 0> sky <0, 1, 0> right -x*image_width/image_height\n"
|
|
1395
|
+
<< "rotate <" << dxfNum(c.vpr[0]) << ", " << dxfNum(c.vpr[1]) << " + clock * 3, " << dxfNum(c.vpr[2])
|
|
1396
|
+
<< " + clock>\n"
|
|
1397
|
+
<< "translate " << povVec(c.vpt[0], c.vpt[1], c.vpt[2]) << "\n"
|
|
1398
|
+
<< "}\n";
|
|
1399
|
+
} else {
|
|
1400
|
+
const double dx = hi[0] - lo[0], dy = hi[1] - lo[1], dz = hi[2] - lo[2];
|
|
1401
|
+
out << "camera { look_at " << povVec((lo[0] + hi[0]) / 2, (lo[1] + hi[1]) / 2, (lo[2] + hi[2]) / 2)
|
|
1402
|
+
<< " location " << povVec(lo[0] + dx * move, lo[1] - dy * move, lo[2] + dz * move)
|
|
1403
|
+
<< " up <0, 0, 1> right <1, 0, 0> sky <0, 0, 1> rotate <-55, clock * 3, clock + 25> right "
|
|
1404
|
+
"x*image_width/image_height }\n";
|
|
1405
|
+
}
|
|
1406
|
+
out << "#include \"rad_def.inc\"\n"
|
|
1407
|
+
<< "global_settings { photons { count 20000 autostop 0 jitter .4 } radiosity { "
|
|
1408
|
+
"Rad_Settings(Radiosity_Normal, off, off) } }\n";
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
namespace {
|
|
1412
|
+
|
|
1158
1413
|
// PDF's own unit is 1/72 inch; models are millimetres.
|
|
1159
1414
|
constexpr double kPtPerMm = 72.0 / 25.4;
|
|
1160
1415
|
// Page margin the ruler is drawn on, in points. OpenSCAD's own MARGIN.
|
|
@@ -1497,8 +1752,8 @@ std::vector<std::string> writePdf(const std::string& path, const std::vector<Col
|
|
|
1497
1752
|
}
|
|
1498
1753
|
|
|
1499
1754
|
const std::vector<std::string>& exportExtensions() {
|
|
1500
|
-
static const std::vector<std::string> exts = {".3mf", ".amf", ".pdf", ".stl", ".obj",
|
|
1501
|
-
".off", ".ply", ".svg", ".wrl", ".x3d"};
|
|
1755
|
+
static const std::vector<std::string> exts = {".3mf", ".amf", ".dxf", ".pdf", ".stl", ".obj",
|
|
1756
|
+
".off", ".ply", ".pov", ".svg", ".wrl", ".x3d"};
|
|
1502
1757
|
return exts;
|
|
1503
1758
|
}
|
|
1504
1759
|
|
|
@@ -1524,6 +1779,12 @@ std::vector<std::string> exportModel(const std::string& path, const std::vector<
|
|
|
1524
1779
|
return writePdf(path, bodies, opts.pdf);
|
|
1525
1780
|
}
|
|
1526
1781
|
|
|
1782
|
+
if (ext == ".dxf") {
|
|
1783
|
+
// 2D, outside the mesh pipeline like SVG and PDF.
|
|
1784
|
+
writeDxf(path, bodies);
|
|
1785
|
+
return warnings;
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1527
1788
|
if (ext == ".svg") {
|
|
1528
1789
|
// 2D, and nothing the mesh pipeline below does applies: no merge,
|
|
1529
1790
|
// no sliver strip, no manifoldness check. Contours are what they
|
|
@@ -1549,6 +1810,8 @@ std::vector<std::string> exportModel(const std::string& path, const std::vector<
|
|
|
1549
1810
|
writeObj(path, objects);
|
|
1550
1811
|
} else if (ext == ".ply") {
|
|
1551
1812
|
writePly(path, objects);
|
|
1813
|
+
} else if (ext == ".pov") {
|
|
1814
|
+
writePov(path, objects, opts.pov);
|
|
1552
1815
|
} else if (ext == ".wrl") {
|
|
1553
1816
|
writeVrml(path, objects);
|
|
1554
1817
|
} else {
|