openscad-cpp-evaluator 1.32.0__tar.gz → 1.34.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.
Files changed (227) hide show
  1. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/CLAUDE.md +28 -3
  2. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/PKG-INFO +1 -1
  3. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/bindings/module.cpp +22 -3
  4. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/export.hpp +30 -0
  5. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/mesh_import.hpp +9 -0
  6. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/pyproject.toml +1 -1
  7. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/python/openscad_cpp_evaluator/__init__.py +8 -2
  8. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/CMakeLists.txt +1 -0
  9. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/import.cpp +18 -4
  10. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/export.cpp +158 -2
  11. openscad_cpp_evaluator-1.34.0/src/import/scene_import.cpp +714 -0
  12. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/import/svg_import.cpp +8 -0
  13. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_dxf_svg_import.cpp +44 -0
  14. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_export.cpp +118 -0
  15. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_import_export.cpp +158 -0
  16. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_python_bindings.py +34 -0
  17. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/uv.lock +1 -1
  18. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/.github/workflows/ci.yml +0 -0
  19. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/.github/workflows/wheels.yml +0 -0
  20. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/.gitignore +0 -0
  21. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/.gitmodules +0 -0
  22. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/CMakeLists.txt +0 -0
  23. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/LICENSE +0 -0
  24. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/README.md +0 -0
  25. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/bindings/CMakeLists.txt +0 -0
  26. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/bindings/ast_to_py.cpp +0 -0
  27. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/cmake/embed_font.cmake +0 -0
  28. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/examples/CMakeLists.txt +0 -0
  29. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/examples/eval_perf_benchmark.cpp +0 -0
  30. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/examples/manifold_cache_reuse.cpp +0 -0
  31. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/examples/minimal_debugger.cpp +0 -0
  32. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  33. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/.gitignore +0 -0
  34. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  35. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  36. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/README.md +0 -0
  37. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  38. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  39. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  40. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  41. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  42. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  43. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  44. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  45. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  46. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  47. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  48. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  49. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  50. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  51. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  52. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  53. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/.DS_Store +0 -0
  54. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  55. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  56. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  57. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  58. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  59. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  60. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  61. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  62. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  63. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  64. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  65. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  66. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  67. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  68. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  69. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  70. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  71. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  72. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  73. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  74. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  75. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  76. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  77. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  78. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  79. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  80. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  81. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  82. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
  83. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  84. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  85. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  86. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  87. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  88. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  89. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  90. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  91. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  92. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  93. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  94. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  95. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  96. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  97. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  98. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
  99. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  100. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  101. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  102. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  103. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  104. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
  105. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  106. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  107. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  108. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  109. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
  110. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  111. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  112. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  113. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  114. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  115. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  116. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  117. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  118. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  119. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
  120. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  121. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  122. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  123. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  124. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  125. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  126. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  127. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  128. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  129. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  130. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  131. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  132. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  133. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  134. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  135. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
  136. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  137. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/resources/fonts/LICENSE +0 -0
  138. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
  139. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
  140. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
  141. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  142. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/booleans.cpp +0 -0
  143. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/builtins.hpp +0 -0
  144. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/call_args.cpp +0 -0
  145. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/color.cpp +0 -0
  146. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/control.cpp +0 -0
  147. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/dxf_dim.cpp +0 -0
  148. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/extrude.cpp +0 -0
  149. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/function_builtins.cpp +0 -0
  150. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/modifiers.cpp +0 -0
  151. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/primitives_2d.cpp +0 -0
  152. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/primitives_3d.cpp +0 -0
  153. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/registry.cpp +0 -0
  154. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/roof.cpp +0 -0
  155. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/segments.cpp +0 -0
  156. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/surface.cpp +0 -0
  157. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/text.cpp +0 -0
  158. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/topology.cpp +0 -0
  159. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/builtins/transforms.cpp +0 -0
  160. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/bytecode_compiler.cpp +0 -0
  161. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/bytecode_vm.cpp +0 -0
  162. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/colored_body.cpp +0 -0
  163. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/coverage.cpp +0 -0
  164. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/csg_generate.cpp +0 -0
  165. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/csg_resolve.cpp +0 -0
  166. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/css_colors.cpp +0 -0
  167. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/debug/debug_repl.cpp +0 -0
  168. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/debug_profile.cpp +0 -0
  169. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/eval_context.cpp +0 -0
  170. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/eval_error.cpp +0 -0
  171. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/eval_use.cpp +0 -0
  172. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/expr_eval.cpp +0 -0
  173. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/format_closure.cpp +0 -0
  174. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/import/dxf_import.cpp +0 -0
  175. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/import/mesh_import.cpp +0 -0
  176. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/import/surface_load.cpp +0 -0
  177. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/manifold_cache.cpp +0 -0
  178. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/measure_geometry.cpp +0 -0
  179. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/mesh_check.cpp +0 -0
  180. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/stmt_eval.cpp +0 -0
  181. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/text/font_match.cpp +0 -0
  182. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/text/freetype_font_provider.cpp +0 -0
  183. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/text/text_metrics.cpp +0 -0
  184. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/user_calls.cpp +0 -0
  185. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/utf8.cpp +0 -0
  186. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/value.cpp +0 -0
  187. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/xkcd_colors.cpp +0 -0
  188. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/xkcd_colors.hpp +0 -0
  189. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/src/zip_stored.cpp +0 -0
  190. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/CMakeLists.txt +0 -0
  191. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_booleans.cpp +0 -0
  192. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_bytecode_compiler.cpp +0 -0
  193. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_children_separate.cpp +0 -0
  194. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_cli.cpp +0 -0
  195. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_control_flow.cpp +0 -0
  196. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_coverage.cpp +0 -0
  197. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_csg_tree.cpp +0 -0
  198. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_debug_hooks.cpp +0 -0
  199. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_discretizer.cpp +0 -0
  200. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_eval_context.cpp +0 -0
  201. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_expr_eval.cpp +0 -0
  202. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_extrude_roof.cpp +0 -0
  203. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_feature_detection.cpp +0 -0
  204. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_function_builtins.cpp +0 -0
  205. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_helpers.hpp +0 -0
  206. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_include_cache.cpp +0 -0
  207. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_manifold_cache.cpp +0 -0
  208. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_mesh_check.cpp +0 -0
  209. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_multi_color_merge.cpp +0 -0
  210. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_primitives.cpp +0 -0
  211. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_profiling.cpp +0 -0
  212. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_render_expr.cpp +0 -0
  213. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_scope_trail.cpp +0 -0
  214. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_scoping.cpp +0 -0
  215. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_surface.cpp +0 -0
  216. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_tail_calls.cpp +0 -0
  217. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_text.cpp +0 -0
  218. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_transforms.cpp +0 -0
  219. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_unexpected_args.cpp +0 -0
  220. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_use.cpp +0 -0
  221. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_value.cpp +0 -0
  222. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_viewport_params.cpp +0 -0
  223. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tests/test_zip_stored.cpp +0 -0
  224. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tools/cli/CMakeLists.txt +0 -0
  225. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tools/cli/cli_lib.cpp +0 -0
  226. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tools/cli/cli_lib.hpp +0 -0
  227. {openscad_cpp_evaluator-1.32.0 → openscad_cpp_evaluator-1.34.0}/tools/cli/main.cpp +0 -0
@@ -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 eleven
1095
- formats `exportExtensions()` lists: 3MF, AMF, DXF, 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,20 @@ 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.
1123
1137
  **`writeDxf` is the third 2D writer**, also on `collect2d()`: OpenSCAD's own `export_dxf.cc`
1124
1138
  layout verbatim (AC1006 header with the extents, one CONTINUOUS linetype, layer 0, every contour
1125
1139
  a closed `LWPOLYLINE` on layer 0 with holes as ordinary contours; 1- and 2-vertex contours as
@@ -1171,10 +1185,21 @@ grep for `ponytail:`.
1171
1185
  - `include/openscad_cpp_evaluator/mesh_import.hpp`, `src/import/mesh_import.cpp` — STL (ASCII +
1172
1186
  binary, exact-match vertex welding)/OBJ/OFF/3MF mesh loaders, returning plain `(verts, tris)` —
1173
1187
  no `Evaluator`/`Value` dependency, so these are reusable from both `import()` contexts below.
1188
+ - `src/import/scene_import.cpp` — AMF, X3D and VRML97 import, the three multi-object formats export
1189
+ writes that nothing could read back (current upstream OpenSCAD removed its AMF importer, so all
1190
+ three go beyond it). Geometry only, like the loaders above, but each format's scene structure is
1191
+ honoured: X3D/VRML `Transform`s nest and apply in full (`T·C·R·SR·S·SR⁻¹·C⁻¹`), `DEF`/`USE`
1192
+ resolves, `ccw FALSE` flips winding, `IndexedFaceSet` polygons fan-triangulate (a last polygon
1193
+ without `-1` counts), and X3D's `IndexedTriangleSet`/`TriangleSet` are read. X3D goes through a
1194
+ small real XML parser (comments, CDATA, DOCTYPE, entities); VRML through a tokenizer + generic
1195
+ node parser that steps over `PROTO`/`EXTERNPROTO`/`ROUTE` (VRML 1.0 is refused by name). AMF's
1196
+ `unit` scales to mm, and a zipped AMF (`PK` header) is read through `readStoredZipEntryBySuffix`.
1197
+ What is not a mesh — primitives (Box, Sphere, ...), `Inline`, AMF constellations — lands in
1198
+ `LoadedMesh::warnings`, which both `import()` faces emit as `import: '<file>': ...`.
1174
1199
  - `include/openscad_cpp_evaluator/import_builtin.hpp`, `include/openscad_cpp_evaluator/
1175
1200
  zip_stored.hpp` (+ `src/zip_stored.cpp`), `src/builtins/import.cpp` — `import()`'s two faces:
1176
1201
  `resolveImport`/`generateImport` (registered in `registry.cpp` like any other builtin *module* —
1177
- a geometry statement, STL/OBJ/OFF/3MF/DXF/SVG) and `importAsValue` (called directly from
1202
+ a geometry statement, STL/OBJ/OFF/3MF/AMF/X3D/VRML/DXF/SVG) and `importAsValue` (called directly from
1178
1203
  `user_calls.cpp`'s `evalFunctionCall`, special-cased *before* the `isBuiltinFunctionName` gate
1179
1204
  since `import` isn't in that table — returns a VNF `[[verts],[faces]]` for a mesh file, a Region
1180
1205
  `[[[x,y],...],...]` for DXF/SVG, or the JSON file's content as native values).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 1.32.0
3
+ Version: 1.34.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -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
 
@@ -233,6 +234,33 @@ std::vector<std::string> writePdf(const std::string& path, const std::vector<Col
233
234
 
234
235
  // -- one entry point ------------------------------------------------------
235
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
+
236
264
  struct ExportOptions {
237
265
  // Empty means "decide from the path's extension".
238
266
  std::string format;
@@ -258,6 +286,8 @@ struct ExportOptions {
258
286
  ExportSvgOptions svg;
259
287
  // .pdf only.
260
288
  ExportPdfOptions pdf;
289
+ // .pov only.
290
+ ExportPovOptions pov;
261
291
  };
262
292
 
263
293
  // Writes `bodies` to `path`, choosing the writer from the extension (or
@@ -13,6 +13,9 @@ namespace oscadeval {
13
13
  struct LoadedMesh {
14
14
  std::vector<std::array<double, 3>> verts;
15
15
  std::vector<std::array<int, 3>> tris;
16
+ // What the loader read but could not turn into mesh (X3D/VRML primitives,
17
+ // Inline, AMF constellations), for import() to warn about.
18
+ std::vector<std::string> warnings;
16
19
  };
17
20
 
18
21
  // Each throws std::runtime_error with a message suitable for wrapping into
@@ -23,5 +26,11 @@ LoadedMesh loadStl(const std::string& path);
23
26
  LoadedMesh loadObj(const std::string& path);
24
27
  LoadedMesh loadOff(const std::string& path);
25
28
  LoadedMesh loadThreeMf(const std::string& path);
29
+ // scene_import.cpp: the three multi-object formats export writes. AMF (plain
30
+ // or zipped, `unit` scaled to mm), X3D and VRML97 (Transforms applied,
31
+ // DEF/USE resolved, polygons fan-triangulated). Geometry only, like the rest.
32
+ LoadedMesh loadAmf(const std::string& path);
33
+ LoadedMesh loadX3d(const std::string& path);
34
+ LoadedMesh loadVrml(const std::string& path);
26
35
 
27
36
  } // namespace oscadeval
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "1.32.0"
7
+ version = "1.34.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -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) -> list:
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
 
@@ -23,6 +23,7 @@ add_library(openscad_cpp_evaluator STATIC
23
23
  mesh_check.cpp
24
24
  zip_stored.cpp
25
25
  import/mesh_import.cpp
26
+ import/scene_import.cpp
26
27
  import/surface_load.cpp
27
28
  import/dxf_import.cpp
28
29
  import/svg_import.cpp
@@ -46,10 +46,16 @@ LoadedMesh loadMeshByExt(const std::string& path, const std::string& ext) {
46
46
  if (ext == ".stl") return loadStl(path);
47
47
  if (ext == ".obj") return loadObj(path);
48
48
  if (ext == ".off") return loadOff(path);
49
+ if (ext == ".amf") return loadAmf(path);
50
+ if (ext == ".x3d") return loadX3d(path);
51
+ if (ext == ".wrl") return loadVrml(path);
49
52
  return loadThreeMf(path);
50
53
  }
51
54
 
52
- bool isMeshExt(const std::string& ext) { return ext == ".stl" || ext == ".obj" || ext == ".off" || ext == ".3mf"; }
55
+ bool isMeshExt(const std::string& ext) {
56
+ return ext == ".stl" || ext == ".obj" || ext == ".off" || ext == ".3mf" || ext == ".amf" || ext == ".x3d" ||
57
+ ext == ".wrl";
58
+ }
53
59
 
54
60
 
55
61
  Value jsonToValue(const nlohmann::ordered_json& j) {
@@ -208,7 +214,10 @@ CSGParams resolveImport(Evaluator& ev, const oscad::ModularCall& node, EvalConte
208
214
  params["dxf"] = Value{ext == ".dxf"};
209
215
  return params;
210
216
  }
211
- if (ext == ".dxf" || ext == ".svg" || ext == ".pdf") {
217
+ // .pdf is not here: it used to be, handed to the SVG parser, which hung on
218
+ // a PDF's bytes. Nothing reads PDF (OpenSCAD does not either), so it takes
219
+ // the ordinary "unsupported file type" error below.
220
+ if (ext == ".dxf" || ext == ".svg") {
212
221
  std::vector<Contour2d> contours;
213
222
  bool filteredMiss = false;
214
223
  try {
@@ -257,6 +266,7 @@ CSGParams resolveImport(Evaluator& ev, const oscad::ModularCall& node, EvalConte
257
266
  } catch (const std::exception& e) {
258
267
  ev.error(std::string("import: ") + e.what(), node);
259
268
  }
269
+ for (const std::string& w : mesh.warnings) ev.warn("import: '" + path + "': " + w, &node.position());
260
270
  std::vector<Value> vertsFlat;
261
271
  vertsFlat.reserve(mesh.verts.size() * 3);
262
272
  for (const auto& v : mesh.verts) {
@@ -428,8 +438,12 @@ Value importAsValue(Evaluator& ev, const CallArgs& args, const oscad::ASTNode& n
428
438
 
429
439
  try {
430
440
  if (ext == ".json") return loadJsonAsValue(path);
431
- if (isMeshExt(ext)) return meshToVnf(loadMeshByExt(path, ext));
432
- if (ext == ".dxf" || ext == ".svg" || ext == ".pdf") {
441
+ if (isMeshExt(ext)) {
442
+ const LoadedMesh mesh = loadMeshByExt(path, ext);
443
+ for (const std::string& w : mesh.warnings) ev.warn("import: '" + path + "': " + w, &node.position());
444
+ return meshToVnf(mesh);
445
+ }
446
+ if (ext == ".dxf" || ext == ".svg") {
433
447
  std::vector<Contour2d> contours;
434
448
  if (ext == ".dxf") {
435
449
  std::optional<std::string> layer;
@@ -915,7 +915,8 @@ std::string lowerExtension(const std::string& path) {
915
915
  }
916
916
 
917
917
  bool isMultiObject(const std::string& ext) {
918
- return ext == ".3mf" || ext == ".amf" || ext == ".obj" || ext == ".ply" || ext == ".wrl" || ext == ".x3d";
918
+ return ext == ".3mf" || ext == ".amf" || ext == ".obj" || ext == ".ply" || ext == ".pov" || ext == ".wrl" ||
919
+ ext == ".x3d";
919
920
  }
920
921
 
921
922
  // The merged single mesh STL/OFF write, with the open shells kept.
@@ -1256,6 +1257,159 @@ void writeDxf(const std::string& path, const std::vector<ColoredBody>& bodies) {
1256
1257
 
1257
1258
  namespace {
1258
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
+
1259
1413
  // PDF's own unit is 1/72 inch; models are millimetres.
1260
1414
  constexpr double kPtPerMm = 72.0 / 25.4;
1261
1415
  // Page margin the ruler is drawn on, in points. OpenSCAD's own MARGIN.
@@ -1599,7 +1753,7 @@ std::vector<std::string> writePdf(const std::string& path, const std::vector<Col
1599
1753
 
1600
1754
  const std::vector<std::string>& exportExtensions() {
1601
1755
  static const std::vector<std::string> exts = {".3mf", ".amf", ".dxf", ".pdf", ".stl", ".obj",
1602
- ".off", ".ply", ".svg", ".wrl", ".x3d"};
1756
+ ".off", ".ply", ".pov", ".svg", ".wrl", ".x3d"};
1603
1757
  return exts;
1604
1758
  }
1605
1759
 
@@ -1656,6 +1810,8 @@ std::vector<std::string> exportModel(const std::string& path, const std::vector<
1656
1810
  writeObj(path, objects);
1657
1811
  } else if (ext == ".ply") {
1658
1812
  writePly(path, objects);
1813
+ } else if (ext == ".pov") {
1814
+ writePov(path, objects, opts.pov);
1659
1815
  } else if (ext == ".wrl") {
1660
1816
  writeVrml(path, objects);
1661
1817
  } else {