openscad-cpp-evaluator 0.32.2__tar.gz → 0.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 (203) hide show
  1. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/CLAUDE.md +41 -2
  2. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/PKG-INFO +1 -1
  3. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/evaluator.hpp +6 -0
  4. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/value.hpp +14 -1
  5. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/pyproject.toml +1 -1
  6. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/CMakeLists.txt +1 -0
  7. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/builtins.hpp +9 -0
  8. openscad_cpp_evaluator-0.34.0/src/builtins/dxf_dim.cpp +221 -0
  9. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/function_builtins.cpp +366 -114
  10. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/registry.cpp +3 -0
  11. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/topology.cpp +70 -0
  12. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/csg_generate.cpp +107 -1
  13. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/eval_context.cpp +6 -0
  14. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/expr_eval.cpp +49 -34
  15. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/value.cpp +169 -65
  16. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_booleans.cpp +180 -0
  17. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_bytecode_compiler.cpp +5 -4
  18. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_control_flow.cpp +2 -2
  19. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_dxf_svg_import.cpp +131 -0
  20. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_expr_eval.cpp +107 -6
  21. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_function_builtins.cpp +151 -5
  22. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_scoping.cpp +12 -0
  23. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_value.cpp +3 -3
  24. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/uv.lock +1 -1
  25. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/.github/workflows/ci.yml +0 -0
  26. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/.github/workflows/wheels.yml +0 -0
  27. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/.gitignore +0 -0
  28. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/.gitmodules +0 -0
  29. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/CMakeLists.txt +0 -0
  30. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/LICENSE +0 -0
  31. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/README.md +0 -0
  32. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/bindings/CMakeLists.txt +0 -0
  33. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/bindings/ast_to_py.cpp +0 -0
  34. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/bindings/module.cpp +0 -0
  35. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/cmake/embed_font.cmake +0 -0
  36. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/examples/CMakeLists.txt +0 -0
  37. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/examples/eval_perf_benchmark.cpp +0 -0
  38. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/examples/manifold_cache_reuse.cpp +0 -0
  39. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/examples/minimal_debugger.cpp +0 -0
  40. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  41. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/.gitignore +0 -0
  42. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  43. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  44. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/README.md +0 -0
  45. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  46. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  47. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  48. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  49. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  50. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  51. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  52. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  53. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  54. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  55. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  56. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  57. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  58. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  59. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  60. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  61. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  62. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  63. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  64. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  65. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  66. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  67. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  68. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  69. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  70. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  71. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  72. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  73. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  74. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  75. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  76. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  77. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  78. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  79. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  80. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  81. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  82. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  83. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  84. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  85. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  86. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  87. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  88. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  89. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  90. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  91. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  92. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  93. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  94. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  95. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  96. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  97. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  98. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  99. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  100. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  101. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  102. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  103. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  104. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  105. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  106. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  107. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
  108. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  109. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  110. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  111. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  112. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  113. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/css_colors.hpp +0 -0
  114. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  115. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  116. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  117. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  118. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  119. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  120. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  121. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
  122. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  123. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  124. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  125. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  126. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  127. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  128. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  129. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  130. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  131. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  132. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  133. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  134. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  135. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  136. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  137. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
  138. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/resources/fonts/LICENSE +0 -0
  139. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  140. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/booleans.cpp +0 -0
  141. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/call_args.cpp +0 -0
  142. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/color.cpp +0 -0
  143. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/control.cpp +0 -0
  144. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/extrude.cpp +0 -0
  145. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/import.cpp +0 -0
  146. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/modifiers.cpp +0 -0
  147. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/primitives_2d.cpp +0 -0
  148. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/primitives_3d.cpp +0 -0
  149. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/roof.cpp +0 -0
  150. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/segments.cpp +0 -0
  151. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/surface.cpp +0 -0
  152. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/text.cpp +0 -0
  153. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/builtins/transforms.cpp +0 -0
  154. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/bytecode_compiler.cpp +0 -0
  155. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/bytecode_vm.cpp +0 -0
  156. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/colored_body.cpp +0 -0
  157. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/csg_resolve.cpp +0 -0
  158. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/css_colors.cpp +0 -0
  159. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/debug/debug_repl.cpp +0 -0
  160. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/debug_profile.cpp +0 -0
  161. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/eval_error.cpp +0 -0
  162. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/eval_use.cpp +0 -0
  163. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/export.cpp +0 -0
  164. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/import/dxf_import.cpp +0 -0
  165. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/import/mesh_import.cpp +0 -0
  166. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/import/surface_load.cpp +0 -0
  167. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/import/svg_import.cpp +0 -0
  168. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/manifold_cache.cpp +0 -0
  169. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/mesh_check.cpp +0 -0
  170. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/stmt_eval.cpp +0 -0
  171. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/text/font_match.cpp +0 -0
  172. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/text/freetype_font_provider.cpp +0 -0
  173. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/text/text_metrics.cpp +0 -0
  174. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/user_calls.cpp +0 -0
  175. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/src/zip_stored.cpp +0 -0
  176. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/CMakeLists.txt +0 -0
  177. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_cli.cpp +0 -0
  178. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_csg_tree.cpp +0 -0
  179. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_debug_hooks.cpp +0 -0
  180. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_eval_context.cpp +0 -0
  181. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_export.cpp +0 -0
  182. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_extrude_roof.cpp +0 -0
  183. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_helpers.hpp +0 -0
  184. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_import_export.cpp +0 -0
  185. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_manifold_cache.cpp +0 -0
  186. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_mesh_check.cpp +0 -0
  187. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_multi_color_merge.cpp +0 -0
  188. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_primitives.cpp +0 -0
  189. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_profiling.cpp +0 -0
  190. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_python_bindings.py +0 -0
  191. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_scope_trail.cpp +0 -0
  192. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_surface.cpp +0 -0
  193. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_tail_calls.cpp +0 -0
  194. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_text.cpp +0 -0
  195. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_transforms.cpp +0 -0
  196. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_unexpected_args.cpp +0 -0
  197. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_use.cpp +0 -0
  198. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_viewport_params.cpp +0 -0
  199. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tests/test_zip_stored.cpp +0 -0
  200. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tools/cli/CMakeLists.txt +0 -0
  201. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tools/cli/cli_lib.cpp +0 -0
  202. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tools/cli/cli_lib.hpp +0 -0
  203. {openscad_cpp_evaluator-0.32.2 → openscad_cpp_evaluator-0.34.0}/tools/cli/main.cpp +0 -0
@@ -512,6 +512,9 @@ grep for `ponytail:`.
512
512
  `Evaluator::evaluate()` also takes an optional `viewportParams` map (added after a test-suite
513
513
  parity review found it missing entirely): seeds arbitrary `$`-prefixed entries into `ctx.dyn`
514
514
  (e.g. `$vpt`/`$vpr`/`$vpd`/`$vpf` from a GUI host's current camera, or `$t` for animation time)
515
+ — note `EvalContext::makeRoot` also seeds `$preview` to **`false`**, always: there is no preview
516
+ mode here, and leaving it undef made the common `$preview ? cheap : real` idiom take the cheap
517
+ branch by accident while warning about an unknown variable
515
518
  before evaluation starts, via a direct `ctx.dyn` write that deliberately never touches
516
519
  `ctx.dynExplicit` — lets a caller tell "the script itself assigned this `$`-var"
517
520
  (`dynExplicit`) apart from "merely present because the caller seeded it" after `evaluate()`
@@ -558,13 +561,49 @@ grep for `ponytail:`.
558
561
  color instead of preserving each part's own, matching real OpenSCAD's actual behavior once fixed
559
562
  (cross-checked triangle-color-count-and-values against the Python reference directly, not just
560
563
  “does it run”).
561
- - `src/builtins/topology.cpp` — `hull()`/`minkowski()`. Both splice their children transparently in
564
+ - `src/builtins/dxf_dim.cpp` — `dxf_dim()`/`dxf_cross()`, which read a measurement out of a DXF file
565
+ rather than out of the model. Ported from the reference's `io/dxfdim.cc` plus the DIMENSION/LINE
566
+ half of `io/DxfData.cc`: `dxf_dim()` returns the first matching DIMENSION's value by its type
567
+ (`70 & 7` — 0 rotated, 1 aligned, 2 angular, 3/4 diameter/radius, 6 ordinate; type 5 is
568
+ unsupported there too), `dxf_cross()` intersects the first two LINE entities. Note the reference's
569
+ own coordinate quirk, reproduced here: groups 11/12/16 (and 21/22/26) are scaled but NOT
570
+ origin-shifted, being extents rather than positions.
571
+
572
+ Deliberately its own group-code walk rather than sharing `src/import/dxf_import.cpp`'s: that one
573
+ produces closed contours, and these need the DIMENSION entities' seven coordinate slots and the
574
+ raw LINE endpoints, neither of which a contour list keeps. One divergence: `dxf_cross()` takes the
575
+ first two LINEs, where the reference walks every 2-point path — for a real cross (two strokes
576
+ meeting in the middle, not at their endpoints) that is the same set.
577
+
578
+ - `src/csg_generate.cpp` — `Evaluator::applyDimensionRules`, run centrally just before every node's
579
+ `GenerateFn` (and once more over the top-level list, which is an implicit union). Mirrors the
580
+ reference's `isValidDim` + `collectChildren2D`/`collectChildren3D`: a node's dimension is fixed by
581
+ its first non-background, non-empty child, and every child of the other dimension is dropped with
582
+ `Mixing 2D and 3D objects is not supported` followed by `Ignoring {N}D child object for {M}D
583
+ operation`. `linear_extrude`/`rotate_extrude`/`offset` are always-2D and `projection` always-3D, so
584
+ they skip the "mixing" line and emit only the second; `roof()` emits neither, matching the
585
+ reference. Background (`%`) children are exempt.
586
+
587
+ Doing this centrally is also what keeps `generateCsg` safe: it builds ONE result and switches on
588
+ whether it holds a `body` or a `section`, so a group that changed dimension part-way dereferenced
589
+ the empty optional -- `union() { cube(1); square(4); }` took the process down with "mutex lock
590
+ failed: Invalid argument". Filtering before dispatch means no `GenerateFn` ever sees a mixed group.
591
+ All 25 module/shape combinations were diffed against OpenSCAD 2026.02.01 warning for warning, with
592
+ the surviving geometry compared by STL volume.
593
+
594
+ - `src/builtins/topology.cpp` — `hull()`/`minkowski()`/`fill()`. All three splice their children transparently in
562
595
  the CSG tree exactly like union/difference/intersection (resolve just evaluates them for the
563
596
  side effect); `hull()` picks an all-3D (`Manifold::Hull`) or all-2D (`CrossSection::Hull`) hull of
564
597
  the *foreground* (role-split) children, falling back to sections only when no child has a body;
565
598
  `minkowski()` only ever operates on 3D bodies (a 2D sibling among the foreground children is
566
599
  silently ignored, matching the reference exactly — no 2D `minkowski_sum` fallback the way hull
567
- has one). Both pass background/highlight/show_only bodies through untouched.
600
+ has one). All pass background/highlight/show_only bodies through untouched. `fill()` is 2D-only
601
+ (a 3D foreground child draws the reference's own `fill() not yet implemented for 3D` warning and
602
+ contributes nothing): it unions the foreground sections, keeps only the outlines with positive
603
+ signed area — outer boundaries, since Manifold winds a hole clockwise — and re-unions those,
604
+ which matters because two outers can overlap once the holes between them are gone. Ported from
605
+ the reference's `applyFill2D`, and checked shape-for-shape against OpenSCAD 2026.02.01 by
606
+ extruding and comparing STL volumes.
568
607
  - `src/builtins/extrude.cpp` — `linear_extrude()`/`rotate_extrude()`/`projection(cut=)`. All three
569
608
  union every 2D child into one `CrossSection` via `toCrossSection` first. `rotate_extrude`'s
570
609
  segment count can't be resolved until generate time (it depends on the merged children's bounds,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 0.32.2
3
+ Version: 0.34.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -330,6 +330,12 @@ public:
330
330
  // free function, same reasoning as tagGenerated()/builtinChildren().
331
331
  void warn(const std::string& message, const oscad::Position* position);
332
332
 
333
+ // Applies OpenSCAD's mixed-2D/3D rules to a node's children just
334
+ // before its GenerateFn runs -- see csg_generate.cpp.
335
+ void applyDimensionRules(CSGNode& node);
336
+ // ruleValue is a DimRule; the enum is file-local to csg_generate.cpp.
337
+ void applyDimensionRulesTo(const std::vector<CSGNode*>& children, int ruleValue);
338
+
333
339
  // Apply `!`: replace the whole tree with the first show_only
334
340
  // subtree, discarding its ancestors and every sibling. See its
335
341
  // definition for why this cannot be done by tagging bodies.
@@ -147,6 +147,12 @@ bool oscComparable(const Value& a, const Value& b);
147
147
  Value scale(double scalarValue, const Value& value);
148
148
  Value divScale(const Value& value, double divisor);
149
149
 
150
+ // `number / vector`, the mirror of divScale's `vector / number` -- the
151
+ // reference divides the scalar by each element in turn (Value.cc's
152
+ // `operator/` NUMBER/VECTOR branch, `*this / vecval`), recursing into
153
+ // nested lists the same way. `5 / [1, 2]` is `[5, 2.5]`, not undef.
154
+ Value divInto(double numerator, const Value& value);
155
+
150
156
  // Elementwise `+`/`-` between two lists (zip semantics: truncates to the
151
157
  // shorter length when lengths differ), or the scalar/mismatched-type
152
158
  // fallback (numeric + numeric, everything else -> undef). `vecAdd` rejects
@@ -167,7 +173,14 @@ Value vecSub(const Value& a, const Value& b);
167
173
  // a Python bool silently). This divergence is undocumented/untested
168
174
  // behavior in the reference implementation -- revisit only if a real
169
175
  // script's `*` on a bool-containing vector is shown to need it.
170
- Value matmul(const Value& a, const Value& b);
176
+ //
177
+ // `error`, when non-null, receives the reference's own diagnostic text for
178
+ // whichever undefined case was hit (multiply_visitor / multvecvec /
179
+ // multmatvec / multvecmat in the reference's Value.cc) -- "vector*vector
180
+ // requires matching lengths (2 != 3)", "Matrix must be rectangular. Problem
181
+ // at row 1", and so on. applyBinaryOp warns with it; a caller that only
182
+ // wants the value can leave it null. It is only written on an undef result.
183
+ Value matmul(const Value& a, const Value& b, std::string* error = nullptr);
171
184
 
172
185
  // OpenSCAD's echo()/str() number formatting: at most 6 significant digits,
173
186
  // fixed-point for exponents in [-5, 5], scientific notation with no leading
@@ -4,7 +4,7 @@ build-backend = "scikit_build_core.build"
4
4
 
5
5
  [project]
6
6
  name = "openscad_cpp_evaluator"
7
- version = "0.32.2"
7
+ version = "0.34.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -29,6 +29,7 @@ add_library(openscad_cpp_evaluator STATIC
29
29
  builtins/call_args.cpp
30
30
  builtins/segments.cpp
31
31
  builtins/registry.cpp
32
+ builtins/dxf_dim.cpp
32
33
  builtins/primitives_2d.cpp
33
34
  builtins/primitives_3d.cpp
34
35
  builtins/transforms.cpp
@@ -160,6 +160,15 @@ CSGParams resolveHull(Evaluator& ev, const oscad::ModularCall& node, EvalContext
160
160
  std::vector<ColoredBody> generateHull(Evaluator& ev, const CSGParams& params,
161
161
  const std::vector<std::unique_ptr<CSGNode>>& children, const oscad::ASTNode& node);
162
162
 
163
+ // dxf_dim()/dxf_cross() -- read a dimension or a cross's centre out of a
164
+ // DXF file. Functions, not modules; dispatched from evalBuiltinFunction.
165
+ Value builtinDxfDim(Evaluator& ev, const CallArgs& args, const oscad::ASTNode& node);
166
+ Value builtinDxfCross(Evaluator& ev, const CallArgs& args, const oscad::ASTNode& node);
167
+
168
+ CSGParams resolveFill(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx);
169
+ std::vector<ColoredBody> generateFill(Evaluator& ev, const CSGParams& params,
170
+ const std::vector<std::unique_ptr<CSGNode>>& children,
171
+ const oscad::ASTNode& node);
163
172
  CSGParams resolveMinkowski(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx);
164
173
  std::vector<ColoredBody> generateMinkowski(Evaluator& ev, const CSGParams& params,
165
174
  const std::vector<std::unique_ptr<CSGNode>>& children,
@@ -0,0 +1,221 @@
1
+ #include "builtins.hpp"
2
+
3
+ #include "openscad_cpp_evaluator/call_args.hpp"
4
+ #include "openscad_cpp_evaluator/evaluator.hpp"
5
+
6
+ #include <cmath>
7
+ #include <filesystem>
8
+ #include <fstream>
9
+ #include <sstream>
10
+
11
+ namespace oscadeval {
12
+
13
+ // dxf_dim() / dxf_cross() -- read a measurement straight out of a DXF file
14
+ // rather than out of the model. Ported from the reference's io/dxfdim.cc
15
+ // plus the DIMENSION/LINE half of io/DxfData.cc.
16
+ //
17
+ // These share the group-code walk with src/import/dxf_import.cpp but not its
18
+ // output: that one only cares about closed contours, while these two need
19
+ // the DIMENSION entities' seven coordinate slots and the raw LINE endpoints,
20
+ // neither of which a contour list keeps.
21
+
22
+ namespace {
23
+
24
+ struct Entity {
25
+ std::string type; // "DIMENSION", "LINE", ...
26
+ std::string layer;
27
+ std::string name; // group 1: DIMENSION's text override
28
+ int dimType = 0; // group 70
29
+ double angle = 0.0; // group 50
30
+ double coords[7][2] = {}; // groups 10-16 / 20-26
31
+ std::vector<double> xverts, yverts; // groups 10/11 and 20/21, in order
32
+ };
33
+
34
+ std::string trimmed(const std::string& s) {
35
+ const size_t b = s.find_first_not_of(" \t\r\n");
36
+ if (b == std::string::npos) return "";
37
+ return s.substr(b, s.find_last_not_of(" \t\r\n") - b + 1);
38
+ }
39
+
40
+ // One entity per group-0 marker. Coordinates carry the origin shift and
41
+ // scale the reference applies while parsing, with its own exception: groups
42
+ // 11, 12 and 16 (and their 21/22/26 partners) are scaled but NOT shifted,
43
+ // since they are extents rather than positions.
44
+ std::vector<Entity> readEntities(const std::string& path, double xorigin, double yorigin, double scale) {
45
+ std::ifstream in(path);
46
+ std::vector<Entity> out;
47
+ if (!in) return out;
48
+
49
+ std::string codeLine, dataLine;
50
+ Entity cur;
51
+ bool started = false;
52
+ while (std::getline(in, codeLine) && std::getline(in, dataLine)) {
53
+ const std::string codeStr = trimmed(codeLine);
54
+ const std::string data = trimmed(dataLine);
55
+ if (codeStr.empty()) continue;
56
+ int code = 0;
57
+ try {
58
+ code = std::stoi(codeStr);
59
+ } catch (...) {
60
+ break;
61
+ }
62
+ const auto num = [&]() -> double {
63
+ try {
64
+ return std::stod(data);
65
+ } catch (...) {
66
+ return 0.0;
67
+ }
68
+ };
69
+
70
+ if (code == 0) {
71
+ if (started) out.push_back(cur);
72
+ cur = Entity{};
73
+ cur.type = data;
74
+ started = true;
75
+ continue;
76
+ }
77
+ if (!started) continue;
78
+
79
+ if (code >= 10 && code <= 16) {
80
+ cur.coords[code - 10][0] =
81
+ (code == 11 || code == 12 || code == 16) ? num() * scale : (num() - xorigin) * scale;
82
+ } else if (code >= 20 && code <= 26) {
83
+ cur.coords[code - 20][1] =
84
+ (code == 21 || code == 22 || code == 26) ? num() * scale : (num() - yorigin) * scale;
85
+ }
86
+ switch (code) {
87
+ case 1: cur.name = data; break;
88
+ case 8: cur.layer = data; break;
89
+ case 10:
90
+ case 11: cur.xverts.push_back((num() - xorigin) * scale); break;
91
+ case 20:
92
+ case 21: cur.yverts.push_back((num() - yorigin) * scale); break;
93
+ case 50: cur.angle = num(); break;
94
+ case 70:
95
+ try {
96
+ cur.dimType = std::stoi(data);
97
+ } catch (...) {
98
+ }
99
+ break;
100
+ default: break;
101
+ }
102
+ }
103
+ if (started) out.push_back(cur);
104
+ return out;
105
+ }
106
+
107
+ double deg(double r) { return r * 180.0 / 3.14159265358979323846; }
108
+ double rad(double d) { return d * 3.14159265358979323846 / 180.0; }
109
+
110
+ struct CommonArgs {
111
+ std::string path;
112
+ std::string rawFile;
113
+ std::string layer;
114
+ double xorigin = 0.0, yorigin = 0.0, scale = 1.0;
115
+ };
116
+
117
+ CommonArgs commonArgs(const CallArgs& args, const oscad::ASTNode& node) {
118
+ CommonArgs c;
119
+ const Value fileArg = getArg(args, 0, "file", Value{});
120
+ c.rawFile = std::holds_alternative<std::string>(fileArg) ? std::get<std::string>(fileArg) : fmtValue(fileArg);
121
+ c.path = resolveFilePath(fileArg, node);
122
+ const Value layerArg = getArg(args, std::nullopt, "layer", Value{});
123
+ if (const std::string* s = std::get_if<std::string>(&layerArg)) c.layer = *s;
124
+ const Value originArg = getArg(args, std::nullopt, "origin", Value{});
125
+ if (const ListPtr* l = std::get_if<ListPtr>(&originArg); l && *l && (*l)->items.size() >= 2) {
126
+ c.xorigin = toDoubleLenient((*l)->items[0]);
127
+ c.yorigin = toDoubleLenient((*l)->items[1]);
128
+ }
129
+ const Value scaleArg = getArg(args, std::nullopt, "scale", Value{1.0});
130
+ if (std::holds_alternative<double>(scaleArg)) c.scale = std::get<double>(scaleArg);
131
+ return c;
132
+ }
133
+
134
+ } // namespace
135
+
136
+ Value builtinDxfDim(Evaluator& ev, const CallArgs& args, const oscad::ASTNode& node) {
137
+ const CommonArgs c = commonArgs(args, node);
138
+ const Value nameArg = getArg(args, std::nullopt, "name", Value{});
139
+ const std::string name = std::holds_alternative<std::string>(nameArg) ? std::get<std::string>(nameArg) : "";
140
+
141
+ if (!std::filesystem::exists(c.path)) {
142
+ ev.warn("Can't open DXF file '" + c.rawFile + "'!", &node.position());
143
+ return Value{};
144
+ }
145
+ for (const Entity& e : readEntities(c.path, c.xorigin, c.yorigin, c.scale)) {
146
+ if (e.type != "DIMENSION") continue;
147
+ if (!c.layer.empty() && c.layer != e.layer) continue;
148
+ if (!name.empty() && e.name != name) continue;
149
+
150
+ const int type = e.dimType & 7;
151
+ if (type == 0) { // rotated, horizontal or vertical
152
+ const double x = e.coords[4][0] - e.coords[3][0];
153
+ const double y = e.coords[4][1] - e.coords[3][1];
154
+ return Value{std::fabs(x * std::cos(rad(e.angle)) + y * std::sin(rad(e.angle)))};
155
+ }
156
+ if (type == 1) { // aligned
157
+ const double x = e.coords[4][0] - e.coords[3][0];
158
+ const double y = e.coords[4][1] - e.coords[3][1];
159
+ return Value{std::sqrt(x * x + y * y)};
160
+ }
161
+ if (type == 2) { // angular
162
+ const double a1 = deg(std::atan2(e.coords[0][0] - e.coords[5][0], e.coords[0][1] - e.coords[5][1]));
163
+ const double a2 = deg(std::atan2(e.coords[4][0] - e.coords[3][0], e.coords[4][1] - e.coords[3][1]));
164
+ return Value{std::fabs(a1 - a2)};
165
+ }
166
+ if (type == 3 || type == 4) { // diameter or radius
167
+ const double x = e.coords[5][0] - e.coords[0][0];
168
+ const double y = e.coords[5][1] - e.coords[0][1];
169
+ return Value{std::sqrt(x * x + y * y)};
170
+ }
171
+ if (type == 6) { // ordinate
172
+ return Value{(e.dimType & 64) ? e.coords[3][0] : e.coords[3][1]};
173
+ }
174
+ // type 5 (angular 3-point) falls through, as in the reference.
175
+ ev.warn("Dimension '" + name + "' in '" + c.rawFile + "', layer '" + c.layer + "' has unsupported type!",
176
+ &node.position());
177
+ return Value{};
178
+ }
179
+ ev.warn("Can't find dimension '" + name + "' in '" + c.rawFile + "', layer '" + c.layer + "'!",
180
+ &node.position());
181
+ return Value{};
182
+ }
183
+
184
+ Value builtinDxfCross(Evaluator& ev, const CallArgs& args, const oscad::ASTNode& node) {
185
+ const CommonArgs c = commonArgs(args, node);
186
+ if (!std::filesystem::exists(c.path)) {
187
+ ev.warn("Can't open DXF file '" + c.rawFile + "'!", &node.position());
188
+ return Value{};
189
+ }
190
+
191
+ // The first two LINEs on the layer are taken to be the cross. The
192
+ // reference walks every 2-point path instead, which for a real cross is
193
+ // the same set: its two strokes meet in the middle rather than at their
194
+ // endpoints, so neither gets joined into a longer path.
195
+ double p[4][2];
196
+ int found = 0;
197
+ for (const Entity& e : readEntities(c.path, c.xorigin, c.yorigin, c.scale)) {
198
+ if (e.type != "LINE") continue;
199
+ if (!c.layer.empty() && c.layer != e.layer) continue;
200
+ if (e.xverts.size() < 2 || e.yverts.size() < 2) continue;
201
+ p[found][0] = e.xverts[0];
202
+ p[found][1] = e.yverts[0];
203
+ ++found;
204
+ p[found][0] = e.xverts[1];
205
+ p[found][1] = e.yverts[1];
206
+ ++found;
207
+ if (found == 4) {
208
+ const double x1 = p[0][0], y1 = p[0][1], x2 = p[1][0], y2 = p[1][1];
209
+ const double x3 = p[2][0], y3 = p[2][1], x4 = p[3][0], y4 = p[3][1];
210
+ const double dem = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
211
+ if (dem == 0.0) break; // parallel: no cross, same as the reference
212
+ const double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / dem;
213
+ std::vector<Value> xy{Value{x1 + ua * (x2 - x1)}, Value{y1 + ua * (y2 - y1)}};
214
+ return Value{std::make_shared<const ValueList>(ValueList{std::move(xy)})};
215
+ }
216
+ }
217
+ ev.warn("Can't find cross in '" + c.rawFile + "', layer '" + c.layer + "'!", &node.position());
218
+ return Value{};
219
+ }
220
+
221
+ } // namespace oscadeval