openscad-cpp-evaluator 1.28.6__tar.gz → 1.29.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 (226) hide show
  1. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/CLAUDE.md +9 -3
  2. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/PKG-INFO +1 -1
  3. openscad_cpp_evaluator-1.29.0/include/openscad_cpp_evaluator/css_colors.hpp +20 -0
  4. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/pyproject.toml +1 -1
  5. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/CMakeLists.txt +1 -0
  6. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/color.cpp +44 -17
  7. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/css_colors.cpp +39 -31
  8. openscad_cpp_evaluator-1.29.0/src/xkcd_colors.cpp +967 -0
  9. openscad_cpp_evaluator-1.29.0/src/xkcd_colors.hpp +13 -0
  10. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_transforms.cpp +103 -30
  11. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/uv.lock +1 -1
  12. openscad_cpp_evaluator-1.28.6/include/openscad_cpp_evaluator/css_colors.hpp +0 -19
  13. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/.github/workflows/ci.yml +0 -0
  14. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/.github/workflows/wheels.yml +0 -0
  15. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/.gitignore +0 -0
  16. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/.gitmodules +0 -0
  17. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/CMakeLists.txt +0 -0
  18. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/LICENSE +0 -0
  19. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/README.md +0 -0
  20. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/bindings/CMakeLists.txt +0 -0
  21. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/bindings/ast_to_py.cpp +0 -0
  22. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/bindings/module.cpp +0 -0
  23. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/cmake/embed_font.cmake +0 -0
  24. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/examples/CMakeLists.txt +0 -0
  25. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/examples/eval_perf_benchmark.cpp +0 -0
  26. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/examples/manifold_cache_reuse.cpp +0 -0
  27. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/examples/minimal_debugger.cpp +0 -0
  28. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/.github/workflows/ci.yml +0 -0
  29. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/.gitignore +0 -0
  30. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/CLAUDE.md +0 -0
  31. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/CMakeLists.txt +0 -0
  32. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/README.md +0 -0
  33. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/api.hpp +0 -0
  34. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/ast_node.hpp +0 -0
  35. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/comments.hpp +0 -0
  36. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/declarations.hpp +0 -0
  37. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/expression.hpp +0 -0
  38. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/module_instantiation.hpp +0 -0
  39. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/scope_builder.hpp +0 -0
  40. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast/vector_element.hpp +0 -0
  41. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/ast.hpp +0 -0
  42. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/comments.hpp +0 -0
  43. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/position.hpp +0 -0
  44. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/pretty_print.hpp +0 -0
  45. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope.hpp +0 -0
  46. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/scope_table.hpp +0 -0
  47. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/serialization.hpp +0 -0
  48. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/include/openscad_cpp_parser/source_map.hpp +0 -0
  49. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/.DS_Store +0 -0
  50. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/CMakeLists.txt +0 -0
  51. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/api.cpp +0 -0
  52. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/ast_node.cpp +0 -0
  53. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/declarations.cpp +0 -0
  54. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/expression.cpp +0 -0
  55. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/format_utils.hpp +0 -0
  56. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/module_instantiation.cpp +0 -0
  57. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/scope_builder.cpp +0 -0
  58. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/ast/vector_element.cpp +0 -0
  59. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/comment_attach_internal.hpp +0 -0
  60. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/comments.cpp +0 -0
  61. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/driver.cpp +0 -0
  62. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/driver.hpp +0 -0
  63. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/lexer.l +0 -0
  64. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/lexer_api.hpp +0 -0
  65. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/oscad_location.hpp +0 -0
  66. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/grammar/parser.y +0 -0
  67. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/inline_comment_attach.cpp +0 -0
  68. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/position.cpp +0 -0
  69. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/pretty_print.cpp +0 -0
  70. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/scope.cpp +0 -0
  71. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/serialization/json_io.cpp +0 -0
  72. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/serialization/yaml_io.cpp +0 -0
  73. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/src/source_map.cpp +0 -0
  74. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/CMakeLists.txt +0 -0
  75. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_assignments.cpp +0 -0
  76. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_ast_generation.cpp +0 -0
  77. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_comments_and_files.cpp +0 -0
  78. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_concurrent_parse.cpp +0 -0
  79. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_const_borrow.cpp +0 -0
  80. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_control.cpp +0 -0
  81. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_expressions.cpp +0 -0
  82. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_functions.cpp +0 -0
  83. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_helpers.hpp +0 -0
  84. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_inline_comments.cpp +0 -0
  85. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_lexical.cpp +0 -0
  86. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_modules.cpp +0 -0
  87. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_node_str.cpp +0 -0
  88. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_pretty_print.cpp +0 -0
  89. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_render_expression.cpp +0 -0
  90. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_scope.cpp +0 -0
  91. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_serialization.cpp +0 -0
  92. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_smoke.cpp +0 -0
  93. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_source_map.cpp +0 -0
  94. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_strict_commas.cpp +0 -0
  95. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_use_include.cpp +0 -0
  96. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tests/test_vectors.cpp +0 -0
  97. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tools/cli/CMakeLists.txt +0 -0
  98. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/external/openscad_cpp_parser/tools/cli/main.cpp +0 -0
  99. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/bound_args.hpp +0 -0
  100. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/bytecode.hpp +0 -0
  101. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/bytecode_compiler.hpp +0 -0
  102. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/bytecode_vm.hpp +0 -0
  103. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/call_args.hpp +0 -0
  104. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/colored_body.hpp +0 -0
  105. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/coverage.hpp +0 -0
  106. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/csg_node.hpp +0 -0
  107. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/debug_hooks.hpp +0 -0
  108. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/debug_repl.hpp +0 -0
  109. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/dispatch.hpp +0 -0
  110. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/dxf_svg_import.hpp +0 -0
  111. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/eval_context.hpp +0 -0
  112. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/eval_error.hpp +0 -0
  113. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/eval_use.hpp +0 -0
  114. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/evaluator.hpp +0 -0
  115. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/export.hpp +0 -0
  116. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/font_match.hpp +0 -0
  117. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/font_provider.hpp +0 -0
  118. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/format_closure.hpp +0 -0
  119. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/freetype_font_provider.hpp +0 -0
  120. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/function_builtins.hpp +0 -0
  121. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/import_builtin.hpp +0 -0
  122. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/manifold_cache.hpp +0 -0
  123. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/mesh_check.hpp +0 -0
  124. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/mesh_import.hpp +0 -0
  125. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/osc_range.hpp +0 -0
  126. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/profile.hpp +0 -0
  127. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/scope_trail.hpp +0 -0
  128. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/segments.hpp +0 -0
  129. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/surface_load.hpp +0 -0
  130. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/text_metrics.hpp +0 -0
  131. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/utf8.hpp +0 -0
  132. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/value.hpp +0 -0
  133. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/include/openscad_cpp_evaluator/zip_stored.hpp +0 -0
  134. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/python/openscad_cpp_evaluator/__init__.py +0 -0
  135. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/resources/fonts/LICENSE +0 -0
  136. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/resources/fonts/LiberationSans-Bold.ttf +0 -0
  137. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/resources/fonts/LiberationSans-BoldItalic.ttf +0 -0
  138. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/resources/fonts/LiberationSans-Italic.ttf +0 -0
  139. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/resources/fonts/LiberationSans-Regular.ttf +0 -0
  140. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/booleans.cpp +0 -0
  141. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/builtins.hpp +0 -0
  142. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/call_args.cpp +0 -0
  143. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/control.cpp +0 -0
  144. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/dxf_dim.cpp +0 -0
  145. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/extrude.cpp +0 -0
  146. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/function_builtins.cpp +0 -0
  147. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/import.cpp +0 -0
  148. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/modifiers.cpp +0 -0
  149. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/primitives_2d.cpp +0 -0
  150. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/primitives_3d.cpp +0 -0
  151. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/registry.cpp +0 -0
  152. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/roof.cpp +0 -0
  153. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/segments.cpp +0 -0
  154. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/surface.cpp +0 -0
  155. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/text.cpp +0 -0
  156. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/topology.cpp +0 -0
  157. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/builtins/transforms.cpp +0 -0
  158. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/bytecode_compiler.cpp +0 -0
  159. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/bytecode_vm.cpp +0 -0
  160. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/colored_body.cpp +0 -0
  161. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/coverage.cpp +0 -0
  162. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/csg_generate.cpp +0 -0
  163. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/csg_resolve.cpp +0 -0
  164. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/debug/debug_repl.cpp +0 -0
  165. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/debug_profile.cpp +0 -0
  166. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/eval_context.cpp +0 -0
  167. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/eval_error.cpp +0 -0
  168. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/eval_use.cpp +0 -0
  169. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/export.cpp +0 -0
  170. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/expr_eval.cpp +0 -0
  171. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/format_closure.cpp +0 -0
  172. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/import/dxf_import.cpp +0 -0
  173. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/import/mesh_import.cpp +0 -0
  174. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/import/surface_load.cpp +0 -0
  175. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/import/svg_import.cpp +0 -0
  176. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/manifold_cache.cpp +0 -0
  177. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/measure_geometry.cpp +0 -0
  178. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/mesh_check.cpp +0 -0
  179. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/stmt_eval.cpp +0 -0
  180. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/text/font_match.cpp +0 -0
  181. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/text/freetype_font_provider.cpp +0 -0
  182. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/text/text_metrics.cpp +0 -0
  183. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/user_calls.cpp +0 -0
  184. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/utf8.cpp +0 -0
  185. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/value.cpp +0 -0
  186. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/src/zip_stored.cpp +0 -0
  187. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/CMakeLists.txt +0 -0
  188. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_booleans.cpp +0 -0
  189. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_bytecode_compiler.cpp +0 -0
  190. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_children_separate.cpp +0 -0
  191. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_cli.cpp +0 -0
  192. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_control_flow.cpp +0 -0
  193. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_coverage.cpp +0 -0
  194. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_csg_tree.cpp +0 -0
  195. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_debug_hooks.cpp +0 -0
  196. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_dxf_svg_import.cpp +0 -0
  197. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_eval_context.cpp +0 -0
  198. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_export.cpp +0 -0
  199. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_expr_eval.cpp +0 -0
  200. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_extrude_roof.cpp +0 -0
  201. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_feature_detection.cpp +0 -0
  202. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_function_builtins.cpp +0 -0
  203. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_helpers.hpp +0 -0
  204. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_import_export.cpp +0 -0
  205. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_include_cache.cpp +0 -0
  206. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_manifold_cache.cpp +0 -0
  207. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_mesh_check.cpp +0 -0
  208. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_multi_color_merge.cpp +0 -0
  209. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_primitives.cpp +0 -0
  210. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_profiling.cpp +0 -0
  211. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_python_bindings.py +0 -0
  212. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_render_expr.cpp +0 -0
  213. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_scope_trail.cpp +0 -0
  214. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_scoping.cpp +0 -0
  215. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_surface.cpp +0 -0
  216. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_tail_calls.cpp +0 -0
  217. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_text.cpp +0 -0
  218. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_unexpected_args.cpp +0 -0
  219. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_use.cpp +0 -0
  220. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_value.cpp +0 -0
  221. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_viewport_params.cpp +0 -0
  222. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tests/test_zip_stored.cpp +0 -0
  223. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tools/cli/CMakeLists.txt +0 -0
  224. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tools/cli/cli_lib.cpp +0 -0
  225. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tools/cli/cli_lib.hpp +0 -0
  226. {openscad_cpp_evaluator-1.28.6 → openscad_cpp_evaluator-1.29.0}/tools/cli/main.cpp +0 -0
@@ -819,9 +819,15 @@ grep for `ponytail:`.
819
819
  geometric-correctness test in Phase 3, not a hypothetical.
820
820
  - `include/openscad_cpp_evaluator/segments.hpp`, `src/builtins/segments.cpp` — `$fn`/`$fa`/`$fs` ->
821
821
  circular-shape segment count (`fnSegments`/`fnSegmentsFromCtx`), used by sphere/cylinder/circle.
822
- - `include/openscad_cpp_evaluator/css_colors.hpp`, `src/css_colors.cpp` — the 148-entry CSS/SVG
823
- color-name table (mechanically ported from the Python reference's own generated table) plus hex
824
- parsing, backing `color()`'s string-name argument.
822
+ - `include/openscad_cpp_evaluator/css_colors.hpp`, `src/css_colors.cpp`, `src/xkcd_colors.{hpp,cpp}` —
823
+ `parseColor`, OpenSCAD's `parse_color` (ColorUtil.cc): CSS Color Level 4 names (148, with
824
+ `rebeccapurple`) plus `transparent` (alpha 0), `"xkcd:<name>"` over the 949 xkcd survey names
825
+ (generated from OpenSCAD's `XkcdColors.h`, CC0), all case-insensitive, then strict `#rgb` /
826
+ `#rgba` / `#rrggbb` / `#rrggbbaa`. `color()` (`src/builtins/color.cpp`) follows `builtin_color`:
827
+ an unreadable string warns `Unable to parse color "…"` and sets NO colour (children keep their
828
+ own, or the outer one) -- it used to draw white; a list fills missing channels with 1 and warns
829
+ outside 0..1; a numeric `alpha` replaces any alpha, a 4-list's included (checked on the 2026.02.01
830
+ binary's 3MF export). `cssColor` (white fallback) is only for SVG/PDF export options.
825
831
  - `src/builtins/{primitives_2d,primitives_3d,transforms,color,booleans,modifiers,control}.cpp` —
826
832
  one file per builtin group, each a `ResolveFn`/`GenerateFn` pair (or a few, where several builtin
827
833
  names share one pair — circle/square/polygon, translate/rotate/scale/mirror/multmatrix/resize,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: openscad_cpp_evaluator
3
- Version: 1.28.6
3
+ Version: 1.29.0
4
4
  Summary: C++ OpenSCAD evaluator with Python bindings
5
5
  Author: NeuSCAD Contributors
6
6
  License-Expression: MIT
@@ -0,0 +1,20 @@
1
+ #pragma once
2
+
3
+ #include <array>
4
+ #include <optional>
5
+ #include <string>
6
+
7
+ namespace oscadeval {
8
+
9
+ // A colour string as OpenSCAD's parse_color reads it (ColorUtil.cc):
10
+ // a CSS Color Level 4 name or OpenSCAD's "transparent" (alpha 0), an
11
+ // "xkcd:<name>" from the xkcd colour survey, all case-insensitive; else
12
+ // "#rgb", "#rgba", "#rrggbb" or "#rrggbbaa". Nothing if it is none of
13
+ // those -- color() then warns and leaves its children's colour alone.
14
+ std::optional<std::array<double, 4>> parseColor(const std::string& text);
15
+
16
+ // parseColor with the alpha replaced, and white for anything unparseable.
17
+ // For export options (SVG/PDF fill and stroke), which have no warning path.
18
+ std::array<double, 4> cssColor(const std::string& name, double alpha = 1.0);
19
+
20
+ } // 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.28.6"
7
+ version = "1.29.0"
8
8
  description = "C++ OpenSCAD evaluator with Python bindings"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -11,6 +11,7 @@ add_library(openscad_cpp_evaluator STATIC
11
11
  bytecode_vm.cpp
12
12
  colored_body.cpp
13
13
  css_colors.cpp
14
+ xkcd_colors.cpp
14
15
  csg_resolve.cpp
15
16
  coverage.cpp
16
17
  csg_generate.cpp
@@ -1,38 +1,63 @@
1
1
  #include "builtins.hpp"
2
2
 
3
+ #include <cstdio>
4
+
3
5
  #include "openscad_cpp_evaluator/call_args.hpp"
4
6
  #include "openscad_cpp_evaluator/css_colors.hpp"
5
7
  #include "openscad_cpp_evaluator/evaluator.hpp"
6
8
 
7
9
  namespace oscadeval {
8
10
 
9
- // color(c = [1,1,1,1], alpha = 1) -- c is a CSS/hex color name, an [r,g,b]
10
- // (alpha from the separate `alpha` argument), or an [r,g,b,a] (alpha taken
11
- // from the list itself, the separate `alpha` argument is ignored in that
12
- // case). Sets the color on ctx for every descendant statement. Mirrors
13
- // _resolve_color/_generate_color.
11
+ // color(c, alpha), as OpenSCAD's builtin_color (ColorNode.cc):
12
+ // - a string goes through parseColor (CSS / "xkcd:" names, hex with or
13
+ // without alpha); one it cannot read warns "Unable to parse color" and
14
+ // leaves the children's colour alone -- inherited from outside, not reset;
15
+ // - a list fills [r, g, b, a] in order, 1.0 for any it lacks, warning on a
16
+ // component outside 0..1;
17
+ // - a numeric `alpha` then replaces the alpha of whatever `c` gave -- even a
18
+ // 4-element list's, and even "#rrggbbaa"'s -- warning when outside 0..1;
19
+ // - anything else for `c`, or no `c` at all, sets no colour (OpenSCAD's
20
+ // unset Color4f is (-1,-1,-1,-1), which is not a colour).
21
+
22
+ namespace {
23
+ std::string oneDecimal(double v) {
24
+ char buf[64];
25
+ std::snprintf(buf, sizeof buf, "%.1f", v);
26
+ return buf;
27
+ }
28
+ } // namespace
14
29
 
15
30
  BuiltinWrapParams computeColorParams(Evaluator& ev, const oscad::ModularCall& node, EvalContext& ctx) {
16
31
  auto [args, effCtx] = resolveCallArgs(ev, node.arguments, ctx);
17
- const Value defaultC =
18
- Value{std::make_shared<const ValueList>(ValueList{{Value{1.0}, Value{1.0}, Value{1.0}, Value{1.0}}})};
19
- Value cArg = getArg(args, 0, "c", defaultC);
20
- const double alpha = toDoubleLenient(getArg(args, 1, "alpha", Value{1.0}));
32
+ const Value cArg = getArg(args, 0, "c");
33
+ const Value alphaArg = getArg(args, 1, "alpha");
21
34
 
22
- std::array<double, 4> rgba{1.0, 1.0, 1.0, 1.0};
35
+ std::optional<std::array<double, 4>> rgba;
23
36
  if (const std::string* s = std::get_if<std::string>(&cArg)) {
24
- rgba = cssColor(*s, alpha);
37
+ rgba = parseColor(*s);
38
+ if (!rgba) ev.warn("Unable to parse color \"" + *s + "\"", &node.position());
25
39
  } else if (const ListPtr* l = std::get_if<ListPtr>(&cArg); l && *l) {
26
40
  const auto& items = (*l)->items;
27
- if (items.size() == 3) {
28
- rgba = {toDoubleLenient(items[0]), toDoubleLenient(items[1]), toDoubleLenient(items[2]), alpha};
29
- } else if (items.size() >= 4) {
30
- rgba = {toDoubleLenient(items[0]), toDoubleLenient(items[1]), toDoubleLenient(items[2]),
31
- toDoubleLenient(items[3])};
41
+ std::array<double, 4> c{1.0, 1.0, 1.0, 1.0};
42
+ for (size_t i = 0; i < 4; ++i) {
43
+ if (i < items.size()) c[i] = toDoubleLenient(items[i]);
44
+ if (c[i] > 1 || c[i] < 0)
45
+ ev.warn("color() expects numbers between 0.0 and 1.0. Value of " + oneDecimal(c[i]) +
46
+ " is out of range",
47
+ &node.position());
32
48
  }
49
+ rgba = c;
50
+ }
51
+ if (const double* a = std::get_if<double>(&alphaArg)) {
52
+ if (rgba) (*rgba)[3] = *a;
53
+ if (*a < 0.0 || *a > 1.0)
54
+ ev.warn("color() expects alpha between 0.0 and 1.0. Value of " + oneDecimal(*a) + " is out of range",
55
+ &node.position());
33
56
  }
34
57
 
35
- EvalContext childCtx = effCtx.childCtx(nullptr, std::optional<std::array<double, 4>>(rgba));
58
+ // No colour: the child context inherits the outer one (childCtx's
59
+ // nullopt), and generateColor passes the children through untouched.
60
+ EvalContext childCtx = effCtx.childCtx(nullptr, rgba);
36
61
  CSGParams params;
37
62
  params["rgba"] = colorToValue(rgba);
38
63
  return BuiltinWrapParams{std::move(params), std::move(childCtx)};
@@ -70,6 +95,8 @@ std::shared_ptr<const std::vector<ColoredBody>> recolorParts(const std::vector<C
70
95
  std::vector<ColoredBody> generateColor(Evaluator& ev, const CSGParams& params,
71
96
  const std::vector<std::unique_ptr<CSGNode>>& children, const oscad::ASTNode&) {
72
97
  const auto rgba = valueToColor(params.at("rgba"));
98
+ // An unreadable colour sets none: the children keep their own.
99
+ if (!rgba) return flattenCsgTree(children);
73
100
  std::vector<ColoredBody> result;
74
101
  for (ColoredBody b : flattenCsgTree(children)) {
75
102
  b.color = rgba;
@@ -1,16 +1,18 @@
1
1
  #include "openscad_cpp_evaluator/css_colors.hpp"
2
+ #include "xkcd_colors.hpp"
2
3
 
3
4
  #include <cctype>
5
+ #include <optional>
4
6
  #include <unordered_map>
5
7
 
6
8
  namespace oscadeval {
7
9
 
8
10
  namespace {
9
11
 
10
- // Generated (not hand-transcribed) from the Python reference's own
11
- // _css_colors.py, itself generated from a live PySide6 install -- see that
12
- // file's docstring for the regeneration recipe and the Qt-vs-CSS3 list
13
- // discrepancy (British-spelling aliases included, `rebeccapurple` excluded).
12
+ // Originally generated from the Python reference's _css_colors.py (itself
13
+ // from a live PySide6 install). Now OpenSCAD's own WebColors.h list: every
14
+ // RGB here matches it, `rebeccapurple` (CSS Color Level 4) is added, and
15
+ // `transparent`, which needs an alpha of 0, is handled in parseColor.
14
16
  const std::unordered_map<std::string, std::array<double, 3>>& colorTable() {
15
17
  static const std::unordered_map<std::string, std::array<double, 3>> table = {
16
18
  {"aliceblue", {0.9411764740943909, 0.9725490212440491, 1.0}},
@@ -132,6 +134,7 @@ const std::unordered_map<std::string, std::array<double, 3>>& colorTable() {
132
134
  {"plum", {0.8666666746139526, 0.6274510025978088, 0.8666666746139526}},
133
135
  {"powderblue", {0.6901960968971252, 0.8784313797950745, 0.9019607901573181}},
134
136
  {"purple", {0.501960813999176, 0.0, 0.501960813999176}},
137
+ {"rebeccapurple", {0.4, 0.2, 0.6}},
135
138
  {"red", {1.0, 0.0, 0.0}},
136
139
  {"rosybrown", {0.7372549176216125, 0.5607843399047852, 0.5607843399047852}},
137
140
  {"royalblue", {0.2549019753932953, 0.4117647111415863, 0.8823529481887817}},
@@ -153,7 +156,6 @@ const std::unordered_map<std::string, std::array<double, 3>>& colorTable() {
153
156
  {"teal", {0.0, 0.501960813999176, 0.501960813999176}},
154
157
  {"thistle", {0.8470588326454163, 0.7490196228027344, 0.8470588326454163}},
155
158
  {"tomato", {1.0, 0.38823530077934265, 0.27843138575553894}},
156
- {"transparent", {0.0, 0.0, 0.0}},
157
159
  {"turquoise", {0.250980406999588, 0.8784313797950745, 0.8156862854957581}},
158
160
  {"violet", {0.9333333373069763, 0.5098039507865906, 0.9333333373069763}},
159
161
  {"wheat", {0.9607843160629272, 0.8705882430076599, 0.7019608020782471}},
@@ -171,38 +173,44 @@ std::string toLower(const std::string& s) {
171
173
  return r;
172
174
  }
173
175
 
174
- int hexDigit(char c) {
175
- if (c >= '0' && c <= '9') return c - '0';
176
- if (c >= 'a' && c <= 'f') return c - 'a' + 10;
177
- if (c >= 'A' && c <= 'F') return c - 'A' + 10;
178
- return 0;
176
+ // OpenSCAD's parse_hex_color (ColorUtil.cc): "#rgb", "#rgba", "#rrggbb" or
177
+ // "#rrggbbaa", every character after '#' a hex digit, or nothing at all.
178
+ std::optional<std::array<double, 4>> parseHex(const std::string& hex) {
179
+ const bool shortForm = hex.size() == 4 || hex.size() == 5;
180
+ const bool longForm = hex.size() == 7 || hex.size() == 9;
181
+ if ((!shortForm && !longForm) || hex[0] != '#') return std::nullopt;
182
+ for (size_t i = 1; i < hex.size(); ++i)
183
+ if (!std::isxdigit(static_cast<unsigned char>(hex[i]))) return std::nullopt;
184
+ const size_t stride = shortForm ? 1 : 2;
185
+ const double channelMax = shortForm ? 15.0 : 255.0;
186
+ std::array<double, 4> rgba{0.0, 0.0, 0.0, 1.0};
187
+ for (size_t i = 0; i < (hex.size() - 1) / stride; ++i)
188
+ rgba[i] = std::stoi(hex.substr(1 + i * stride, stride), nullptr, 16) / channelMax;
189
+ return rgba;
179
190
  }
180
191
 
181
192
  } // namespace
182
193
 
183
- std::array<double, 4> cssColor(const std::string& name, double alpha) {
184
- if (!name.empty() && name[0] == '#') {
185
- const std::string h = name.substr(1);
186
- if (h.size() == 6) {
187
- const double r = (hexDigit(h[0]) * 16 + hexDigit(h[1])) / 255.0;
188
- const double g = (hexDigit(h[2]) * 16 + hexDigit(h[3])) / 255.0;
189
- const double b = (hexDigit(h[4]) * 16 + hexDigit(h[5])) / 255.0;
190
- return {r, g, b, alpha};
191
- }
192
- if (h.size() == 3) {
193
- const double r = hexDigit(h[0]) / 15.0;
194
- const double g = hexDigit(h[1]) / 15.0;
195
- const double b = hexDigit(h[2]) / 15.0;
196
- return {r, g, b, alpha};
197
- }
198
- return {1.0, 1.0, 1.0, alpha};
194
+ std::optional<std::array<double, 4>> parseColor(const std::string& text) {
195
+ // OpenSCAD's parse_color: a name first (case-insensitive; "xkcd:" reaches
196
+ // the xkcd survey table, falling back to the CSS table), then hex.
197
+ const std::string name = toLower(text);
198
+ if (name.rfind("xkcd:", 0) == 0) {
199
+ const auto& xk = xkcdColorTable();
200
+ if (auto it = xk.find(name.substr(5)); it != xk.end())
201
+ return std::array<double, 4>{it->second[0] / 255.0, it->second[1] / 255.0, it->second[2] / 255.0, 1.0};
199
202
  }
203
+ // OpenSCAD's own addition to the CSS list: fully transparent black.
204
+ if (name == "transparent") return std::array<double, 4>{0.0, 0.0, 0.0, 0.0};
205
+ if (auto it = colorTable().find(name); it != colorTable().end())
206
+ return std::array<double, 4>{it->second[0], it->second[1], it->second[2], 1.0};
207
+ return parseHex(text);
208
+ }
200
209
 
201
- auto it = colorTable().find(toLower(name));
202
- if (it != colorTable().end()) {
203
- return {it->second[0], it->second[1], it->second[2], alpha};
204
- }
205
- return {1.0, 1.0, 1.0, alpha};
210
+ std::array<double, 4> cssColor(const std::string& name, double alpha) {
211
+ auto c = parseColor(name);
212
+ if (!c) return {1.0, 1.0, 1.0, alpha};
213
+ return {(*c)[0], (*c)[1], (*c)[2], alpha};
206
214
  }
207
215
 
208
216
  } // namespace oscadeval