Compare commits
464 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a5195b0a0 | |||
| beb35029a4 | |||
| 4c3d1484c5 | |||
| e0c1b8adbd | |||
| 604515cfb3 | |||
| 57d789c0aa | |||
| 4e9656ea9a | |||
| 07160d9366 | |||
| c111b5f2fb | |||
| 4594d81f7a | |||
| 2e3448f348 | |||
| e5c6e3ef1e | |||
| 57df47b763 | |||
| 42145719a0 | |||
| 64421a2cb9 | |||
| 711e41233f | |||
| cf0508e5c8 | |||
| bace1a1228 | |||
| bda8b6b2e8 | |||
| 52765304cd | |||
| ec526d2b3d | |||
| 3b3d93f333 | |||
| 05f30c1674 | |||
| bba2fc1400 | |||
| 538d7fcb43 | |||
| 8be56316f6 | |||
| eda51873aa | |||
| d4144ddf9b | |||
| c39f44e190 | |||
| 5b8d8416e9 | |||
| 1f2356fa7b | |||
| e29e32f197 | |||
| 76e009ab10 | |||
| 441d67f9ff | |||
| 6541a4e980 | |||
| 85197c1224 | |||
| ed66adac5c | |||
| e88295ceba | |||
| aeca117045 | |||
| 31326e9898 | |||
| a9e9f8b82b | |||
| 8558b37e44 | |||
| aa244bcee4 | |||
| eaf3acc297 | |||
| c392791f2c | |||
| 0fb2e9b06b | |||
| b410c577e0 | |||
| d95b8208b3 | |||
| 99f8cff454 | |||
| 3292cba4ad | |||
| 6fa023b3ab | |||
| 510378d965 | |||
| c8a9159ac5 | |||
| fca86a414e | |||
| b76fcae341 | |||
| e64202417f | |||
| 6a4b5c90c8 | |||
| 2e981d66e8 | |||
| ef0914ff94 | |||
| 0476154973 | |||
| 5e265089c7 | |||
| 31a0c99a2c | |||
| ce3b0d4086 | |||
| d782d45cce | |||
| 9a44641970 | |||
| 2b1ca94e2d | |||
| f30fce0fc1 | |||
| f4b74fcb1b | |||
| 59efc86826 | |||
| 24ce89e0fc | |||
| a476e645b0 | |||
| 3385d1c570 | |||
| f0acea0992 | |||
| 6047c0d5a1 | |||
| 34c378c063 | |||
| dc6e25250c | |||
| 2e22ff8035 | |||
| cb9b50b11e | |||
| a22aeaaf93 | |||
| d4eeedbf95 | |||
| c512c8e86a | |||
| 1bcc1125f0 | |||
| 7c013333db | |||
| 7e0f8a9a4c | |||
| 18e200f262 | |||
| bd0f0f3471 | |||
| e39d741862 | |||
| ea9ea7bba8 | |||
| 07fa5e4f1f | |||
| 2a51f42495 | |||
| 8f259d5b83 | |||
| a6b9d5a5b2 | |||
| 18e4b9ea9f | |||
| 7cccb2b52e | |||
| 7d7a1ecfa5 | |||
| 1202a79e25 | |||
| fbafdfdcb6 | |||
| 2744063631 | |||
| 8e53d5050e | |||
| fde56d3c8b | |||
| 81a6a3dcde | |||
| 3eb76a8b3b | |||
| 60de59d5a9 | |||
| ad0b5c9d05 | |||
| ff08eb0043 | |||
| 6bfd53a55a | |||
| 709cb62fe8 | |||
| ee4786cd8f | |||
| 6a4fef151f | |||
| d3574dd493 | |||
| d2a3430147 | |||
| 598556bca9 | |||
| 80341ec13b | |||
| 7be5d93e51 | |||
| 5bb3b6717f | |||
| 5b6e5815a3 | |||
| 376c313214 | |||
| ab665ee3b3 | |||
| f0d47e1d26 | |||
| a2365228ab | |||
| e2a7a45c44 | |||
| fa21db7df8 | |||
| 4fda59af80 | |||
| 776dfc9c18 | |||
| 6583c28231 | |||
| 6b24775413 | |||
| c4f9269409 | |||
| 9b31d29443 | |||
| e16647a63f | |||
| 5281734a22 | |||
| b5fe8776b5 | |||
| 8986a670e5 | |||
| c528964363 | |||
| 251c20bef0 | |||
| 3c0d4e120e | |||
| bfd6aa9b7d | |||
| 44d7c1fb6f | |||
| db696ec24b | |||
| a69c5770a4 | |||
| da23eb1377 | |||
| 5d9e4d5f95 | |||
| 75b3fb678c | |||
| 827713cc2f | |||
| 4cf104ea2c | |||
| 4fd8f8475c | |||
| 9fdf380286 | |||
| affe37bcc3 | |||
| 9d8ab72da7 | |||
| 160662ffec | |||
| b5550d01c1 | |||
| fd5d0e6738 | |||
| 0067dcab28 | |||
| 2f6ca7e46b | |||
| c2f66107cf | |||
| ec5f4b8740 | |||
| 91aefd5abc | |||
| f1c2fc8804 | |||
| d7cba9e96d | |||
| 849bb392d2 | |||
| 3b77567932 | |||
| 810a9558bd | |||
| d7ae568790 | |||
| 43a549d967 | |||
| 7228e218bf | |||
| 67b491671f | |||
| 60b9e9d188 | |||
| ca005237a1 | |||
| 213e05da5f | |||
| 251d18588a | |||
| 97f48a9f63 | |||
| 72a265e4fc | |||
| 3877ef08b9 | |||
| cce337f83f | |||
| 5304294107 | |||
| b8eb8d262c | |||
| 28cbca72c5 | |||
| 9d18034e13 | |||
| d61ec60480 | |||
| c4538c53e1 | |||
| b6b0d80332 | |||
| 42166bd6b7 | |||
| 5bd5be9543 | |||
| 2f09c90542 | |||
| 8311ae5c5d | |||
| 4973638b56 | |||
| 8a61069fbb | |||
| 55bea620c7 | |||
| c755e067f5 | |||
| f73479ddf2 | |||
| 772815b4c0 | |||
| 6d89de1f5a | |||
| 6375529b44 | |||
| bdd7605d47 | |||
| ffbaf292f0 | |||
| 2b4f07a0e8 | |||
| 4b1556d102 | |||
| 0fe5bf114c | |||
| 526cdfd247 | |||
| ee6b85605a | |||
| 045cfed6a7 | |||
| 5f60d78658 | |||
| 646eb97eaf | |||
| 2cf8df2ef6 | |||
| 0096e694dd | |||
| c29bd18190 | |||
| 8e9e270027 | |||
| 1b927421f6 | |||
| 8d22b3a41a | |||
| edcf02c0d4 | |||
| b85d5a665c | |||
| a232df7751 | |||
| 4757c3cee6 | |||
| 736f334301 | |||
| e721004f62 | |||
| 88d87729d4 | |||
| c7597ea66f | |||
| f3389c3af7 | |||
| a0a52f6657 | |||
| cc9787f80e | |||
| 8e80d98610 | |||
| f8a8114843 | |||
| 98bfe1af9c | |||
| ffbf9836cc | |||
| 806adb6c46 | |||
| 250ed2f266 | |||
| 56f07a5598 | |||
| dfdad35d08 | |||
| 1cef0d83df | |||
| a99c57ffc7 | |||
| cdffdcbbef | |||
| 4f05716f69 | |||
| f0567d6a48 | |||
| 6e9ffe83d2 | |||
| 2647ec51fc | |||
| 23587433e2 | |||
| 0414de7b98 | |||
| 295bd0e165 | |||
| 0b34d3590d | |||
| aedbf0b1d4 | |||
| a13e0e0ceb | |||
| 6f05c19c42 | |||
| db0c25522e | |||
| e6c999bbcd | |||
| 180a725c0e | |||
| 4ba6a9744b | |||
| ae998906ff | |||
| 634f0a2308 | |||
| 306b78ce16 | |||
| 678da425da | |||
| fc499441e2 | |||
| 1cf5f83924 | |||
| 6a465abee9 | |||
| 89a3e89d62 | |||
| 58c0fc396f | |||
| 0952686c1b | |||
| 64b506dccf | |||
| 61195235d8 | |||
| 6241decaf9 | |||
| 3288adf3dd | |||
| 5b53a1354a | |||
| 579dddaea0 | |||
| 9052b69e81 | |||
| 2c5d875ab7 | |||
| 04efc68578 | |||
| 0e137b947f | |||
| 97a24941d2 | |||
| c2a19bf375 | |||
| e40d7aaee7 | |||
| 2b18b68307 | |||
| b9ae8814d4 | |||
| f3a4c62240 | |||
| dbf38d84ef | |||
| f913a2a459 | |||
| f504c82216 | |||
| df18823d0a | |||
| 0396b2d00a | |||
| b1c132bc9a | |||
| 71b3a70254 | |||
| bcdecd19f4 | |||
| 3b3f860adc | |||
| f0d5666a74 | |||
| f1c2f67d63 | |||
| 32900556e0 | |||
| bf14bf3678 | |||
| f0a5fc5016 | |||
| ad1652683b | |||
| 0d778e074b | |||
| 0b2d51d301 | |||
| bf7979d4a7 | |||
| 5439bfc0b5 | |||
| c2ea096abb | |||
| 085853315d | |||
| 332f96c26a | |||
| 56e752c182 | |||
| 014ccf5ff4 | |||
| ab309f2219 | |||
| 6c9afc6f7e | |||
| aff8106205 | |||
| 8ced905843 | |||
| 21340ba019 | |||
| 8b25fa0ae4 | |||
| c0b0369aa2 | |||
| 44a9f9ee42 | |||
| f331a0740b | |||
| 12636b67be | |||
| 9f5ac92faa | |||
| 6e39efd4ac | |||
| 3c40edd12a | |||
| 81b620d7aa | |||
| 9af2ae9a0f | |||
| 1754318df7 | |||
| f273195144 | |||
| 247a77e1b1 | |||
| ce4212a33a | |||
| 522bd95254 | |||
| b0b1e6832e | |||
| 3cb9aa07b5 | |||
| 60f6836ab7 | |||
| 43f0438fbb | |||
| ded10b52da | |||
| 4bc5bdc791 | |||
| 1baaebd3ef | |||
| 97e467f2d1 | |||
| 665ff84495 | |||
| 07b3b92703 | |||
| ddf56e1246 | |||
| 0ddbe87935 | |||
| 19dc8b6881 | |||
| 3e2e229dd1 | |||
| c8d9a4bfdd | |||
| 6c764dce06 | |||
| 655e771455 | |||
| 15f74b7981 | |||
| 9b607f6f1f | |||
| ab67126eec | |||
| 3b8cbc4e22 | |||
| f59f6698f1 | |||
| bd1525dcfb | |||
| 1e5eb1e3b8 | |||
| a1483d63c1 | |||
| 491687d4c1 | |||
| 66bd64cc5e | |||
| f9146cdd58 | |||
| 23e7ac767e | |||
| 3ac7a196c9 | |||
| 202e713cf1 | |||
| 63923da2ca | |||
| 7e22aed739 | |||
| 966b10e731 | |||
| 99eda4cd1b | |||
| 47292bb2bd | |||
| 37dc878f31 | |||
| 7da02460d8 | |||
| f73f4da665 | |||
| ef5985f841 | |||
| 71bb4f7c98 | |||
| 92af4a21c8 | |||
| 5d6c5bab39 | |||
| 8251be9c06 | |||
| 3d744cc8a2 | |||
| 1447bc772a | |||
| 7b24a1dc1e | |||
| d95f40ac88 | |||
| 82ac9a6b03 | |||
| 6ab46b6488 | |||
| 991082fbaf | |||
| 4d338ba2eb | |||
| 94b399e98f | |||
| 5aa41703f7 | |||
| d9aa73b597 | |||
| 6e4e94a8a8 | |||
| ae2a5b2c0d | |||
| 81cbcef31c | |||
| e3d9090e6c | |||
| b8e93270b4 | |||
| ef628d1c86 | |||
| d93b1cb282 | |||
| a66a517c40 | |||
| f3ee34d372 | |||
| c94d1e9894 | |||
| 46a2d6b53c | |||
| c9935007e8 | |||
| 7b9d37c787 | |||
| aa1fe28ddf | |||
| 8f1b456275 | |||
| 8a6a064d37 | |||
| f35f3197c3 | |||
| 78499f44af | |||
| 5b5201f1a6 | |||
| f28ff15ffb | |||
| 4f8bbec9fb | |||
| 77ebf1326c | |||
| fdc95337cf | |||
| 0e053e5e61 | |||
| 6bbb4276c0 | |||
| 6d641c87c4 | |||
| 553f5fb9b8 | |||
| 88dd699715 | |||
| c092e0551b | |||
| c320dc421c | |||
| 0f489a5777 | |||
| 3df709be63 | |||
| 875ac2ce49 | |||
| 698275874f | |||
| 0d4470cd8c | |||
| 5dfc3481c1 | |||
| b596bfc730 | |||
| d11d268597 | |||
| 4b0ba62c69 | |||
| 313d2bdb41 | |||
| 079f6e61e6 | |||
| 4a781b8cd8 | |||
| 5b0eb08473 | |||
| 87206f20c8 | |||
| 5a24d4095a | |||
| 9df8837d43 | |||
| 409ab1ed45 | |||
| 5e03fe2f4b | |||
| 37a586dd61 | |||
| a79f40a711 | |||
| b5728f284b | |||
| 5965439a15 | |||
| 586a358ed4 | |||
| 7770f8982d | |||
| 72ad6383ef | |||
| 0537623a75 | |||
| 65d288227e | |||
| fedb3bcdb1 | |||
| 097b8b7550 | |||
| af7ca3a8a2 | |||
| 27ddb725c7 | |||
| a06bdf5cfc | |||
| 33fdcdb3a0 | |||
| c07ab5f8f9 | |||
| fea32f8aac | |||
| 4927214976 | |||
| b621819c0c | |||
| ec552a5300 | |||
| e0cc740cc3 | |||
| 5de48e916d | |||
| 80af7bbe3e | |||
| 191e983423 | |||
| 2b9445b049 | |||
| 7ddf48ca16 | |||
| d2f6848377 | |||
| 0b6d6fecd8 | |||
| fa691707c2 | |||
| b9a55c74e2 | |||
| 2bb9c81069 | |||
| cedb51b8ea | |||
| 66d13059dd | |||
| 800ea40c0d | |||
| 20442eecd3 | |||
| 22d1cd7032 | |||
| 6a0dc18655 | |||
| e006dbf1af | |||
| 8241a750fa | |||
| 41779cf7bb | |||
| b01b9689c8 | |||
| 4426da6f5d | |||
| 5ead82e627 | |||
| c29b0d2f13 | |||
| 480fd8d517 | |||
| 4c09fa5355 |
@@ -350,7 +350,7 @@ jobs:
|
||||
name: macOS build ${{ matrix.arch }}
|
||||
needs: version
|
||||
if: needs.version.outputs.build == 'true'
|
||||
runs-on: macos-14
|
||||
runs-on: macos-15
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -384,7 +384,7 @@ jobs:
|
||||
name: macOS universal
|
||||
needs: [version, macos-build]
|
||||
if: needs.version.outputs.build == 'true'
|
||||
runs-on: macos-14
|
||||
runs-on: macos-15
|
||||
env:
|
||||
SOLIDCRAFT_VERSION: ${{ needs.version.outputs.version }}
|
||||
SOLIDCRAFT_BUILD_DATE: ${{ needs.version.outputs.date }}
|
||||
|
||||
@@ -84,6 +84,8 @@ Editable drawing code, native projects and shipped exports are collected under `
|
||||
| docs/book/src/generated/tool-preview.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/tool-preview.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| assets/fonts/liberation-sans/LiberationSans-Regular.ttf | Red Hat, Inc. (Liberation Fonts 2.x; digitized data Google) | https://github.com/liberationfonts (Debian fonts-liberation), unmodified; licence text in assets/fonts/liberation-sans/OFL.txt; used for sketch Text outlines | SIL OFL 1.1 |
|
||||
| assets/fonts/biz-udp-gothic/BIZUDPGothic-Regular.ttf | The BIZ UDGothic Project Authors | https://github.com/googlefonts/morisawa-biz-ud-gothic (Google Fonts), unmodified; licence text in assets/fonts/biz-udp-gothic/OFL.txt; used for web UI Japanese font | SIL OFL 1.1 |
|
||||
| assets/fonts/craft-ui-sc/CraftUI-SC.otf | Adobe / Google Inc. (Noto Sans SC); SolidCraft subset | https://github.com/notofonts/noto-cjk Sans/SubsetOTF/SC Regular, glyph-subset for assets/locales/zh.json and renamed Craft UI SC (OFL reserved-name); licence text in assets/fonts/craft-ui-sc/OFL.txt; web UI Simplified Chinese | SIL OFL 1.1 |
|
||||
| assets/fonts/craft-ui-tc/CraftUI-TC.otf | Adobe / Google Inc. (Noto Sans TC); SolidCraft subset | https://github.com/notofonts/noto-cjk Sans/SubsetOTF/TC Regular, glyph-subset for assets/locales/zh-TW.json and renamed Craft UI TC (OFL reserved-name); licence text in assets/fonts/craft-ui-tc/OFL.txt; web UI Traditional Chinese | SIL OFL 1.1 |
|
||||
| tests/step-conformance/cone_point.step | step-conformance contributors | generated from formulas by https://github.com/dan335/step-conformance (corpus/generated, 96f30bb); import regression fixture | CC0-1.0 |
|
||||
| tests/step-conformance/cone_point_vertex.step | step-conformance contributors | generated from formulas by https://github.com/dan335/step-conformance (corpus/generated, 96f30bb); import regression fixture | CC0-1.0 |
|
||||
| tests/step-conformance/cylinder.step | step-conformance contributors | generated from formulas by https://github.com/dan335/step-conformance (corpus/generated, 96f30bb); import regression fixture | CC0-1.0 |
|
||||
@@ -125,6 +127,8 @@ Editable drawing code, native projects and shipped exports are collected under `
|
||||
| assets/appearances/library.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
|
||||
| assets/appearances/opaque_finishes.rs | SolidCraft contributors | original illustrative opaque finish values; no external dataset, textures or measured engineering data | MIT OR Apache-2.0 |
|
||||
| assets/fonts/biz-udp-gothic/OFL.txt | The BIZ UDGothic Project Authors | Unmodified accompanying font licence | SIL OFL 1.1 |
|
||||
| assets/fonts/craft-ui-sc/OFL.txt | Adobe / Google Inc. (Noto CJK); SolidCraft header | Accompanying OFL for CraftUI-SC.otf | SIL OFL 1.1 |
|
||||
| assets/fonts/craft-ui-tc/OFL.txt | Adobe / Google Inc. (Noto CJK); SolidCraft header | Accompanying OFL for CraftUI-TC.otf | SIL OFL 1.1 |
|
||||
| assets/fonts/ibm-plex-mono/OFL.txt | IBM Corp. | Unmodified accompanying font licence | SIL OFL 1.1 |
|
||||
| assets/fonts/ibm-plex-sans/OFL.txt | IBM Corp. | Unmodified accompanying font licence | SIL OFL 1.1 |
|
||||
| assets/fonts/liberation-sans/OFL.txt | Red Hat, Inc.; Liberation Fonts contributors | Unmodified accompanying font licence | SIL OFL 1.1 |
|
||||
@@ -185,11 +189,7 @@ Editable drawing code, native projects and shipped exports are collected under `
|
||||
| assets/shaders/viewport.wgsl | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
|
||||
| assets/styles/ui/palettes.rs | SolidCraft contributors | Original SolidCraft resource data or drawing code, collected without redesign | MIT OR Apache-2.0 |
|
||||
| assets/styles/ui/themes/gruvbox-dark.json | SolidCraft contributors | original SolidCraft theme file mapping SolidCraft's UI colours to the Gruvbox palette's colour values (Gruvbox by Pavel Pertsev, https://github.com/morhetz/gruvbox, MIT) | MIT OR Apache-2.0 |
|
||||
| assets/styles/ui/themes/gruvbox-dark-hard.json | SolidCraft contributors | original SolidCraft theme file mapping SolidCraft's UI colours to the Gruvbox palette's colour values (Gruvbox by Pavel Pertsev, https://github.com/morhetz/gruvbox, MIT) | MIT OR Apache-2.0 |
|
||||
| assets/styles/ui/themes/gruvbox-dark-soft.json | SolidCraft contributors | original SolidCraft theme file mapping SolidCraft's UI colours to the Gruvbox palette's colour values (Gruvbox by Pavel Pertsev, https://github.com/morhetz/gruvbox, MIT) | MIT OR Apache-2.0 |
|
||||
| assets/styles/ui/themes/gruvbox-light.json | SolidCraft contributors | original SolidCraft theme file mapping SolidCraft's UI colours to the Gruvbox palette's colour values (Gruvbox by Pavel Pertsev, https://github.com/morhetz/gruvbox, MIT) | MIT OR Apache-2.0 |
|
||||
| assets/styles/ui/themes/gruvbox-light-hard.json | SolidCraft contributors | original SolidCraft theme file mapping SolidCraft's UI colours to the Gruvbox palette's colour values (Gruvbox by Pavel Pertsev, https://github.com/morhetz/gruvbox, MIT) | MIT OR Apache-2.0 |
|
||||
| assets/styles/ui/themes/gruvbox-light-soft.json | SolidCraft contributors | original SolidCraft theme file mapping SolidCraft's UI colours to the Gruvbox palette's colour values (Gruvbox by Pavel Pertsev, https://github.com/morhetz/gruvbox, MIT) | MIT OR Apache-2.0 |
|
||||
| assets/styles/ui/themes/solidcraft-95.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
|
||||
| assets/styles/ui/themes/platinum-9.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
|
||||
| assets/styles/ui/themes/cupertino.json | SolidCraft contributors | original SolidCraft theme file | MIT OR Apache-2.0 |
|
||||
@@ -610,6 +610,26 @@ Original SolidCraft drawings, Open for owner review; no runtime assignments.
|
||||
| assets/icons/ui/design/svg/flat/status_pin.svg | SolidCraft contributors | Original analytic pin icon for persistent viewport results | MIT OR Apache-2.0 |
|
||||
| assets/locales/pending/render-wear.json | SolidCraft contributors | Original UI labels and translations | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/equation_curve.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
|
||||
| assets/locales/pending/sketch-recent-snap.json | SolidCraft contributors | Original preference messages for the recent centre and midpoint snap | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_horizontal.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_vertical.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_angle.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_parallel.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_perpendicular.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_tangent_external.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_tangent_at.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_tangent_two.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/construction_line_bisector.svg | SolidCraft contributors | original icon master (64 grid) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-circle.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-circle.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-flower.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-flower.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-involute.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-involute.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-line.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-line.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-parabola.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-parabola.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-spiral.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-spiral.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| docs/book/src/generated/equation-wave.png | SolidCraft contributors | rendered by `cargo xtask book` (`solidcraft-cli snapshot docs/book/scripts/equation-wave.json`; gitignored) | MIT OR Apache-2.0 |
|
||||
| assets/icons/ui/design/svg/model/print_face.svg | SolidCraft contributors | two-tone modelling icon master (64 grid), original SolidCraft artwork | MIT OR Apache-2.0 |
|
||||
| assets/locales/fi.json | SolidCraft contributors | Original Finnish translation of SolidCraft's English catalog, AI-assisted (Claude Code) clean-room from the English and not yet reviewed line by line by a native speaker; no commercial CAD text used | MIT OR Apache-2.0 |
|
||||
|
||||
## Code adapted from sibling projects
|
||||
|
||||
@@ -669,6 +689,7 @@ copied into SolidCraft.
|
||||
|
||||
| Directory | Source | Licence | Changes |
|
||||
|---|---|---|---|
|
||||
| vendor/accesskit_macos | accesskit_macos 0.26.3, https://github.com/AccessKit/accesskit (The AccessKit contributors) | MIT OR Apache-2.0 | the subclassing adapter and its tests from 0.27.2: dropping the adapter keeps AppKit's key-value observers (vendor/README.md) |
|
||||
| vendor/truck-meshalgo | truck-meshalgo 0.4.0, https://github.com/ricosjp/truck (RICOS Co. Ltd.) | Apache-2.0 | meshing: bounded parameter searches, collapsed-boundary projection, subdivision and provisional fixed-grid previews (vendor/README.md) |
|
||||
| vendor/truck-stepio | truck-stepio 0.3.0, https://github.com/ricosjp/truck (RICOS Co. Ltd.) | Apache-2.0 | STEP writer: intersection-curve surfaces written at unique ids (vendor/README.md) |
|
||||
| vendor/truck-shapeops | truck-shapeops 0.4.0, https://github.com/ricosjp/truck (RICOS Co. Ltd.) | Apache-2.0 | robust meshing and nearest-parameter fallback in booleans; degenerate intersection-curve rejection; face and edge history of booleans; trace macro; corner choice at vertices several intersection curves end on; reuse of an operand's meshes (vendor/README.md) |
|
||||
|
||||
@@ -60,8 +60,6 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "accesskit_macos"
|
||||
version = "0.26.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ce02dc63b43f0c9296af9ac946312a2dc8814427d7a64d2d600971dac55b6076"
|
||||
dependencies = [
|
||||
"accesskit",
|
||||
"accesskit_consumer 0.38.0",
|
||||
@@ -4210,7 +4208,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"block2 0.6.2",
|
||||
"eframe",
|
||||
@@ -4242,15 +4240,16 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
"winit",
|
||||
"x11rb",
|
||||
"zbus 5.19.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-3dx-client"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-cli"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
@@ -4262,7 +4261,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-derive"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -4271,7 +4270,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-doc"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
@@ -4288,7 +4287,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-engine"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
@@ -4309,7 +4308,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-geom"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -4318,7 +4317,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-gpu"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"log",
|
||||
@@ -4338,7 +4337,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-io"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"cadmpeg-core",
|
||||
"cadmpeg-ir",
|
||||
@@ -4362,7 +4361,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-kernel"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"log",
|
||||
"proptest",
|
||||
@@ -4382,7 +4381,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-mcp"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
"solidcraft-engine",
|
||||
@@ -4391,7 +4390,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-render"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"image",
|
||||
"moxcms",
|
||||
@@ -4405,7 +4404,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-sketch"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"harfrust",
|
||||
"serde",
|
||||
@@ -4418,14 +4417,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-space-mouse"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-ui-egui"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"arboard",
|
||||
"egui",
|
||||
@@ -4444,6 +4443,7 @@ dependencies = [
|
||||
"solidcraft-gpu",
|
||||
"solidcraft-space-mouse",
|
||||
"syn 2.0.119",
|
||||
"sys-locale",
|
||||
"tiny-skia",
|
||||
"toml",
|
||||
"ttf-parser",
|
||||
@@ -4455,7 +4455,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "solidcraft-web"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"eframe",
|
||||
"egui",
|
||||
@@ -4559,6 +4559,18 @@ dependencies = [
|
||||
"syn 2.0.119",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sys-locale"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.27.0"
|
||||
@@ -4566,7 +4578,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.4",
|
||||
"getrandom 0.4.3",
|
||||
"once_cell",
|
||||
"rustix 1.1.5",
|
||||
"windows-sys 0.61.2",
|
||||
@@ -5998,7 +6010,7 @@ checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7"
|
||||
|
||||
[[package]]
|
||||
name = "xtask"
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"serde",
|
||||
|
||||
@@ -5,7 +5,7 @@ members = ["crates/*", "apps/*", "xtask"]
|
||||
exclude = ["vendor"]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.27.0"
|
||||
version = "0.29.0"
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
rust-version = "1.95"
|
||||
@@ -165,6 +165,9 @@ egui-wgpu = { path = "vendor/egui-wgpu" }
|
||||
# winit 0.30 never binds and eframe 0.36 still requires winit 0.30.
|
||||
winit = { path = "vendor/winit" }
|
||||
|
||||
# macOS: dropping the accessibility adapter leaves AppKit's key-value observers intact (#7535).
|
||||
accesskit_macos = { path = "vendor/accesskit_macos" }
|
||||
|
||||
# Mutation testing (cargo-mutants, docs/mutation-testing.md): the ci profile with incremental
|
||||
# builds, since every mutant rebuilds the crates above the one it changes.
|
||||
[profile.mutants]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Third-party software in SolidCraft
|
||||
|
||||
SolidCraft (the desktop app, solidcraft-cli and the web app) is built from the 560 crates below.
|
||||
SolidCraft (the desktop app, solidcraft-cli and the web app) is built from the 561 crates below.
|
||||
Generated by `cargo xtask licences` from Cargo.lock and the crates' own licence files.
|
||||
SolidCraft's own licence is in LICENSE-MIT and LICENSE-APACHE, and NOTICE.
|
||||
|
||||
@@ -403,6 +403,7 @@ syn 1.0.109 (MIT OR Apache-2.0)
|
||||
syn 2.0.119 (MIT OR Apache-2.0)
|
||||
syn 3.0.6 (MIT OR Apache-2.0)
|
||||
synstructure 0.13.2 (MIT)
|
||||
sys-locale 0.3.2 (MIT OR Apache-2.0)
|
||||
tempfile 3.27.0 (MIT OR Apache-2.0)
|
||||
termcolor 1.4.1 (Unlicense OR MIT)
|
||||
thiserror 1.0.69 (MIT OR Apache-2.0)
|
||||
@@ -1836,8 +1837,8 @@ approx 0.4.0, as-raw-xcb-connection 1.0.1, atspi 0.29.0, atspi-common 0.13.0, at
|
||||
cgmath 0.18.0, chardetng 0.1.17, codespan-reporting 0.13.1, encoding_rs 0.8.42, kurbo 0.13.1,
|
||||
multiversion_no_op 1.0.0, nohash-hasher 0.2.0, peniko 0.6.1, polycool 0.4.0, raw-window-metal 1.1.0,
|
||||
rustls-platform-verifier 0.7.1, self_cell 1.3.0, siphasher 1.0.4, spade 2.15.1, static_assertions
|
||||
1.1.0, ureq 3.4.2, ureq-proto 0.6.4, utf8_iter 1.0.4, x11rb 0.13.2, x11rb-protocol 0.13.2, zeroize
|
||||
1.9.1, zeroize_derive 1.5.0, zune-core 0.5.3, zune-jpeg 0.5.15
|
||||
1.1.0, sys-locale 0.3.2, ureq 3.4.2, ureq-proto 0.6.4, utf8_iter 1.0.4, x11rb 0.13.2, x11rb-protocol
|
||||
0.13.2, zeroize 1.9.1, zeroize_derive 1.5.0, zune-core 0.5.3, zune-jpeg 0.5.15
|
||||
================================================================================
|
||||
|
||||
Apache License
|
||||
@@ -13570,6 +13571,32 @@ The above copyright notice and this permission notice shall be included in all c
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
sys-locale 0.3.2
|
||||
================================================================================
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 1Password
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
================================================================================
|
||||
tempfile 3.27.0
|
||||
================================================================================
|
||||
@@ -16799,6 +16826,14 @@ Bundled fonts (SIL Open Font License, Version 1.1)
|
||||
Copyright 2022 The BIZ UDGothic Project Authors (https://github.com/googlefonts/morisawa-biz-ud-mincho)
|
||||
Source: https://github.com/googlefonts/morisawa-biz-ud-gothic
|
||||
|
||||
- CraftUI-SC.otf (assets/fonts/craft-ui-sc/CraftUI-SC.otf)
|
||||
Copyright 2014-2021 Adobe / Google Inc. (Noto Sans SC subset for SolidCraft web zh)
|
||||
Source: https://github.com/notofonts/noto-cjk (Sans SubsetOTF/SC)
|
||||
|
||||
- CraftUI-TC.otf (assets/fonts/craft-ui-tc/CraftUI-TC.otf)
|
||||
Copyright 2014-2021 Adobe / Google Inc. (Noto Sans TC subset for SolidCraft web zh-TW)
|
||||
Source: https://github.com/notofonts/noto-cjk (Sans SubsetOTF/TC)
|
||||
|
||||
- IBMPlexSans-Variable.ttf (assets/fonts/ibm-plex-sans/IBMPlexSans-Variable.ttf)
|
||||
Copyright 2017 IBM Corp. with Reserved Font Name "Plex"
|
||||
Source: https://github.com/IBM/plex
|
||||
|
||||
@@ -720,11 +720,8 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
|
||||
eprintln!("solidcraft mcp: the design's folder is left out because {why}; add it with --allow-path if you mean it");
|
||||
}
|
||||
}
|
||||
// How a headless session treats calls that break a command's parameter contract.
|
||||
// How calls that break a command's parameter contract are treated, headless or bridged.
|
||||
let param_check = parse_param_check("mcp", args)?;
|
||||
if param_check != solidcraft_engine::schema::ParamCheck::Off && flag(args, "--connect").is_some() {
|
||||
eprintln!("solidcraft mcp: --param-check applies to headless sessions; calls to the app are not checked yet");
|
||||
}
|
||||
let backend: Box<dyn solidcraft_mcp::Backend> = match (flag(args, "--connect"), flag(args, "--in")) {
|
||||
(Some(_), Some(_)) => return Err("mcp: use either --connect or --in, not both".into()),
|
||||
(Some(addr), None) => {
|
||||
@@ -732,7 +729,7 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
|
||||
return Err(format!("mcp: --connect wants HOST:PORT, such as 127.0.0.1:7878, not `{addr}`"));
|
||||
};
|
||||
// Serve without the app too: the tools connect once it runs, and say it isn't until then.
|
||||
let mut remote = solidcraft_mcp::Remote::new(addr, flag(args, "--token"));
|
||||
let mut remote = solidcraft_mcp::Remote::new(addr, flag(args, "--token")).with_param_check(param_check);
|
||||
if let Err(e) = remote.try_connect() {
|
||||
eprintln!(
|
||||
"solidcraft mcp: no SolidCraft app at {addr} yet ({e}); start it with `solidcraft --control {port}` \
|
||||
@@ -752,7 +749,8 @@ fn cmd_mcp(args: &[String]) -> Result<(), String> {
|
||||
let auto = !args.iter().any(|a| a == "--headless");
|
||||
if auto && let Some(port) = discover_app() {
|
||||
eprintln!("solidcraft mcp: bridged to the running app at 127.0.0.1:{port} (--headless starts a session of its own)");
|
||||
return serve_mcp(Box::new(solidcraft_mcp::Remote::new(&format!("127.0.0.1:{port}"), flag(args, "--token"))), scope);
|
||||
let remote = solidcraft_mcp::Remote::new(&format!("127.0.0.1:{port}"), flag(args, "--token")).with_param_check(param_check);
|
||||
return serve_mcp(Box::new(remote), scope);
|
||||
}
|
||||
let mut headless = solidcraft_mcp::Headless::default();
|
||||
headless.session.param_check = param_check;
|
||||
|
||||
@@ -229,7 +229,9 @@ fn known_pending_concepts_and_released_files_round_trip_with_inert_metadata() {
|
||||
assert!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr));
|
||||
let reopened = io::read_design(&std::fs::read(&destination).unwrap()).unwrap();
|
||||
assert_eq!(reopened.metadata, document.metadata);
|
||||
assert_eq!(reopened.name, document.name);
|
||||
// #4907: `run --save` maps to Save As, and a borrowed design name
|
||||
// follows the destination file's stem instead of keeping the old name.
|
||||
assert_eq!(reopened.name, format!("resaved-{index}"));
|
||||
assert_eq!(reopened.features, document.features);
|
||||
assert_eq!(std::fs::read(&source).unwrap(), bytes);
|
||||
}
|
||||
|
||||
@@ -123,3 +123,42 @@ fn a_design_naming_a_sketch_and_its_extrude_alike_replays_from_its_script() {
|
||||
assert_eq!(names, ["Block", "Block"], "{first:#}");
|
||||
assert_eq!(second["commands"], first["commands"], "the replayed design's script has the same steps");
|
||||
}
|
||||
|
||||
/// #10230: script export must disclose the print-face state that replay leaves out.
|
||||
#[test]
|
||||
fn script_export_warns_about_omitted_print_faces_on_stderr() {
|
||||
let dir = std::env::temp_dir().join(format!("solidcraft-print-face-script-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let saved = dir.join("block.sc");
|
||||
let exported = dir.join("block.json");
|
||||
let mut s = Session::default();
|
||||
s.execute("solid.box", &json!({"length": 20, "width": 10, "height": 5, "body_name": "Block"})).unwrap();
|
||||
s.execute("body.print_face", &json!({"body": "Block", "point": [10, 5, 0]})).unwrap();
|
||||
s.execute("file.save", &json!({"path": saved})).unwrap();
|
||||
let native = std::fs::read(&saved).unwrap();
|
||||
|
||||
for to_file in [false, true] {
|
||||
let mut cmd = std::process::Command::new(env!("CARGO_BIN_EXE_solidcraft-cli"));
|
||||
cmd.arg("script").arg(&saved);
|
||||
if to_file {
|
||||
cmd.arg("--out").arg(&exported);
|
||||
}
|
||||
let out = cmd.output().unwrap();
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
assert!(out.status.success(), "{stderr}");
|
||||
assert!(stderr.contains("note: the script leaves out print-face assignments (body.print_face)"), "{stderr}");
|
||||
let script = if to_file {
|
||||
assert!(out.stdout.is_empty(), "--out must keep stdout empty");
|
||||
std::fs::read(&exported).unwrap()
|
||||
} else {
|
||||
out.stdout
|
||||
};
|
||||
let script: Value = serde_json::from_slice(&script).unwrap();
|
||||
let mut replayed = Session::default();
|
||||
replayed.run_script(&script).unwrap();
|
||||
assert!(replayed.doc.print_faces.is_empty());
|
||||
assert_eq!(replayed.doc.features, s.doc.features);
|
||||
assert_eq!(std::fs::read(&saved).unwrap(), native, "export must not change the source design");
|
||||
}
|
||||
std::fs::remove_dir_all(dir).unwrap();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
<link data-trunk rel="rust" data-bin="solidcraft-web" data-wasm-opt="z" data-weak-refs />
|
||||
<link data-trunk rel="copy-file" href="../../assets/fonts/biz-udp-gothic/BIZUDPGothic-Regular.ttf" data-target-path="fonts" />
|
||||
<link data-trunk rel="copy-file" href="../../assets/fonts/biz-udp-gothic/OFL.txt" data-target-path="fonts" />
|
||||
<link data-trunk rel="copy-file" href="../../assets/fonts/craft-ui-sc/CraftUI-SC.otf" data-target-path="fonts" />
|
||||
<link data-trunk rel="copy-file" href="../../assets/fonts/craft-ui-sc/OFL.txt" data-target-path="fonts/craft-ui-sc" />
|
||||
<link data-trunk rel="copy-file" href="../../assets/fonts/craft-ui-tc/CraftUI-TC.otf" data-target-path="fonts" />
|
||||
<link data-trunk rel="copy-file" href="../../assets/fonts/craft-ui-tc/OFL.txt" data-target-path="fonts/craft-ui-tc" />
|
||||
<link data-trunk rel="css" href="../../assets/styles/web/loading.css" />
|
||||
<link data-trunk rel="copy-file" href="../../assets/styles/web/loading-logo.svg" />
|
||||
<!-- Installable as an app (manifest.webmanifest); the icons are the Linux exports of the app mark. -->
|
||||
|
||||
@@ -273,8 +273,10 @@ mod web {
|
||||
}
|
||||
|
||||
const JAPANESE_FONT_PATH: &str = "./fonts/BIZUDPGothic-Regular.ttf";
|
||||
const CHINESE_SC_FONT_PATH: &str = "./fonts/CraftUI-SC.otf";
|
||||
const CHINESE_TC_FONT_PATH: &str = "./fonts/CraftUI-TC.otf";
|
||||
|
||||
type FontLoadResult = Rc<std::cell::RefCell<Option<Result<Vec<u8>, String>>>>;
|
||||
type FontLoadResult = Rc<std::cell::RefCell<Option<Result<(String, Vec<u8>), String>>>>;
|
||||
|
||||
struct Shell {
|
||||
app: SolveApp,
|
||||
@@ -292,11 +294,17 @@ mod web {
|
||||
rename_focus: bool,
|
||||
/// The start page's recent designs were filled from the stored ones.
|
||||
recents_synced: bool,
|
||||
/// On-demand CJK font: fetched only when a CJK language is selected.
|
||||
/// On-demand script fonts: fetched only when a CJK language is selected.
|
||||
font: solidcraft_ui_egui::fonts::CjkFontLoader,
|
||||
font_result: FontLoadResult,
|
||||
/// The fetched CJK font's bytes: kept so a language change can re-order the fallbacks.
|
||||
/// The fetched Japanese font's bytes: kept so a language change can re-order the fallbacks.
|
||||
cjk_bytes: Option<Vec<u8>>,
|
||||
/// The fetched Chinese font's bytes (Simplified or Traditional for this session).
|
||||
chinese_bytes: Option<Vec<u8>>,
|
||||
/// Which Chinese face `chinese_bytes` is: `"zh"` or `"zh-TW"`.
|
||||
chinese_kind: Option<&'static str>,
|
||||
/// Kind requested by the in-flight fetch (`"ja"`, `"zh"`, or `"zh-TW"`).
|
||||
font_fetch_kind: Option<&'static str>,
|
||||
/// The language the fonts were last set up for (a CJK UI leads with the CJK face).
|
||||
font_language: String,
|
||||
space_mouse: SpaceMouse,
|
||||
@@ -674,65 +682,102 @@ mod web {
|
||||
files::autosave(&self.files, None);
|
||||
}
|
||||
|
||||
/// Fetch and install the CJK font when a CJK language is selected. If that fails, this
|
||||
/// Whether the shell already has the on-demand face the live language needs.
|
||||
fn script_font_ready(&self) -> bool {
|
||||
match solidcraft_ui_egui::fonts::web_script_font_kind(solidcraft_ui_egui::i18n::effective_language(&self.app.preferences.language)) {
|
||||
Some("zh") => self.chinese_bytes.is_some() && self.chinese_kind == Some("zh"),
|
||||
Some("zh-TW") => self.chinese_bytes.is_some() && self.chinese_kind == Some("zh-TW"),
|
||||
Some("ja") => self.cjk_bytes.is_some(),
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch and install a script font when a CJK language is selected. If that fails, this
|
||||
/// session falls back to English (no tofu); the saved language preference is kept.
|
||||
fn tick_font(&mut self, ctx: &egui::Context) {
|
||||
let done = self.font_result.borrow_mut().take();
|
||||
if let Some(res) = done {
|
||||
let kind = self.font_fetch_kind.take();
|
||||
let installed = match res {
|
||||
Ok(bytes) => {
|
||||
self.cjk_bytes = Some(bytes);
|
||||
Ok((path, bytes)) => {
|
||||
match kind {
|
||||
Some("zh") => {
|
||||
self.chinese_bytes = Some(bytes);
|
||||
self.chinese_kind = Some("zh");
|
||||
}
|
||||
Some("zh-TW") => {
|
||||
self.chinese_bytes = Some(bytes);
|
||||
self.chinese_kind = Some("zh-TW");
|
||||
}
|
||||
_ => {
|
||||
self.cjk_bytes = Some(bytes);
|
||||
}
|
||||
}
|
||||
log::info!("loaded web script font from {path}");
|
||||
true
|
||||
}
|
||||
Err(err) => {
|
||||
log::warn!("failed to fetch CJK font from {JAPANESE_FONT_PATH}: {err}");
|
||||
let path = match kind {
|
||||
Some("zh") => CHINESE_SC_FONT_PATH,
|
||||
Some("zh-TW") => CHINESE_TC_FONT_PATH,
|
||||
_ => JAPANESE_FONT_PATH,
|
||||
};
|
||||
log::warn!("failed to fetch script font from {path}: {err}");
|
||||
false
|
||||
}
|
||||
};
|
||||
if installed {
|
||||
log::info!("loaded web CJK font from {JAPANESE_FONT_PATH}");
|
||||
} else if solidcraft_ui_egui::fonts::needs_cjk_font(&self.app.preferences.language) {
|
||||
log::warn!("CJK font unavailable; showing English for this session");
|
||||
let effective = solidcraft_ui_egui::i18n::effective_language(&self.app.preferences.language);
|
||||
if !installed && solidcraft_ui_egui::fonts::needs_cjk_font(effective) {
|
||||
log::warn!("script font unavailable; showing English for this session");
|
||||
}
|
||||
self.font.finished(installed, &mut self.app.preferences.language);
|
||||
self.apply_fonts(ctx);
|
||||
ctx.request_repaint();
|
||||
}
|
||||
if self.font.tick(&mut self.app.preferences.language) {
|
||||
self.fetch_font(ctx);
|
||||
let ready = self.script_font_ready();
|
||||
let effective = solidcraft_ui_egui::i18n::effective_language(&self.app.preferences.language);
|
||||
if self.font.tick(&mut self.app.preferences.language, ready) {
|
||||
self.fetch_font(ctx, solidcraft_ui_egui::fonts::web_script_font_kind(effective).unwrap_or("ja"));
|
||||
}
|
||||
// The CJK face leads only a CJK UI: its Cyrillic glyphs are full-width, so switching
|
||||
// to Ukrainian (or English) must put the Latin face back in front.
|
||||
if self.app.preferences.language != self.font_language {
|
||||
if solidcraft_ui_egui::i18n::effective_language(&self.app.preferences.language) != self.font_language {
|
||||
self.apply_fonts(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set up the UI fonts for the live language, keeping the fetched CJK font as a fallback
|
||||
/// (it leads only for a CJK UI, see [`solidcraft_ui_egui::fonts::install_cjk_font_for`]).
|
||||
/// Set up the UI fonts for the live language, keeping fetched script fonts as fallbacks
|
||||
/// (Chinese leads a Chinese UI; see [`solidcraft_ui_egui::fonts::install_web_script_fonts`]).
|
||||
fn apply_fonts(&mut self, ctx: &egui::Context) {
|
||||
match self.cjk_bytes.clone() {
|
||||
Some(bytes) => {
|
||||
solidcraft_ui_egui::fonts::install_cjk_font_for(ctx, bytes, &self.app.preferences.language);
|
||||
}
|
||||
None => solidcraft_ui_egui::fonts::setup_fonts(ctx),
|
||||
let effective = solidcraft_ui_egui::i18n::effective_language(&self.app.preferences.language);
|
||||
if self.cjk_bytes.is_none() && self.chinese_bytes.is_none() {
|
||||
solidcraft_ui_egui::fonts::setup_fonts(ctx);
|
||||
} else {
|
||||
solidcraft_ui_egui::fonts::install_web_script_fonts(ctx, self.cjk_bytes.clone(), self.chinese_bytes.clone(), effective);
|
||||
}
|
||||
self.font_language.clone_from(&self.app.preferences.language);
|
||||
self.font_language = effective.to_owned();
|
||||
}
|
||||
|
||||
/// CJK text on screen with no CJK font yet (an English UI showing a Japanese name):
|
||||
/// fetch the font, so the text does not stay tofu (#720).
|
||||
/// CJK text on screen with no Japanese font yet (an English UI showing a Japanese name):
|
||||
/// fetch the Japanese font, so the text does not stay tofu (#720).
|
||||
fn watch_text_for_font(&mut self, ctx: &egui::Context) {
|
||||
if self.font.watching_text() && solidcraft_ui_egui::fonts::painted_cjk(ctx) && self.font.text_needs_font() {
|
||||
self.fetch_font(ctx);
|
||||
self.fetch_font(ctx, "ja");
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch_font(&self, ctx: &egui::Context) {
|
||||
fn fetch_font(&mut self, ctx: &egui::Context, kind: &'static str) {
|
||||
let path = match kind {
|
||||
"zh" => CHINESE_SC_FONT_PATH,
|
||||
"zh-TW" => CHINESE_TC_FONT_PATH,
|
||||
_ => JAPANESE_FONT_PATH,
|
||||
};
|
||||
self.font_fetch_kind = Some(kind);
|
||||
let slot = self.font_result.clone();
|
||||
let ctx = ctx.clone();
|
||||
let path = path.to_owned();
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
let res = fetch_font_bytes(JAPANESE_FONT_PATH).await;
|
||||
let res = fetch_font_bytes(&path).await.map(|bytes| (path, bytes));
|
||||
*slot.borrow_mut() = Some(res);
|
||||
ctx.request_repaint();
|
||||
});
|
||||
@@ -962,6 +1007,9 @@ mod web {
|
||||
font: Default::default(),
|
||||
font_result: Rc::new(std::cell::RefCell::new(None)),
|
||||
cjk_bytes: None,
|
||||
chinese_bytes: None,
|
||||
chinese_kind: None,
|
||||
font_fetch_kind: None,
|
||||
font_language,
|
||||
space_mouse: SpaceMouse::default(),
|
||||
wheel_gestures: solidcraft_ui_egui::WebWheelGestures::default(),
|
||||
|
||||
@@ -104,5 +104,10 @@ winit = { version = "0.30", default-features = false, features = ["x11"] }
|
||||
raw-window-handle = "0.6"
|
||||
x11rb = { version = "0.13", default-features = false }
|
||||
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
# The desktop's dark or light preference through the XDG Desktop Portal (src/desktop_theme.rs,
|
||||
# #7944); already in the tree through eframe's accessibility support (accesskit_unix).
|
||||
zbus = { version = "5", default-features = false, features = ["async-io", "blocking-api"] }
|
||||
|
||||
[build-dependencies]
|
||||
embed-resource = "3.0.11"
|
||||
|
||||
@@ -413,11 +413,37 @@ impl Lines {
|
||||
}
|
||||
}
|
||||
|
||||
/// A subscribed connection's seat on the watch: it leaves exactly once, whichever thread sees
|
||||
/// the connection's end first — the connection's own thread at the end of the stream, or the
|
||||
/// events thread at the first write a closed client refuses. The seat used to wait for the
|
||||
/// events thread alone, and that thread only leaves its wait when the design moves, so the
|
||||
/// count could outlive the connection by a second or more (#8315).
|
||||
struct Seat(Mutex<Option<Subscriber>>);
|
||||
|
||||
impl Seat {
|
||||
fn new(counted: Subscriber) -> Self {
|
||||
Seat(Mutex::new(Some(counted)))
|
||||
}
|
||||
|
||||
/// Leave the watch now: the seat goes once, whoever gets here first.
|
||||
fn release(&self) {
|
||||
let counted = self.0.lock().unwrap_or_else(PoisonError::into_inner).take();
|
||||
drop(counted);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Seat {
|
||||
fn drop(&mut self) {
|
||||
self.release();
|
||||
}
|
||||
}
|
||||
|
||||
/// A connection's `control.subscribe` (#6985): its `design.changed` lines, sent from a thread of
|
||||
/// their own until the connection ends.
|
||||
struct Subscription {
|
||||
lines: Arc<Lines>,
|
||||
stop: Arc<AtomicBool>,
|
||||
seat: Arc<Seat>,
|
||||
}
|
||||
|
||||
impl Subscription {
|
||||
@@ -433,15 +459,17 @@ impl Subscription {
|
||||
) -> Option<(Self, std::io::Result<()>)> {
|
||||
let lines = Arc::new(Lines { socket: out.try_clone().ok()?, turn: Mutex::new(()) });
|
||||
let stop = Arc::new(AtomicBool::new(false));
|
||||
let seat = Arc::new(Seat::new(counted));
|
||||
let first = lines.turn.lock().unwrap_or_else(PoisonError::into_inner);
|
||||
let (l, s) = (lines.clone(), stop.clone());
|
||||
let (l, s, watch_seat) = (lines.clone(), stop.clone(), Arc::clone(&seat));
|
||||
// The connection's seat on the watch rides the events thread: it leaves when the thread
|
||||
// does, so the next failed write to a closed client retires it even while the connection's
|
||||
// own thread is slow to see the end of the stream (#7226).
|
||||
std::thread::Builder::new().stack_size(64 * 1024).spawn(move || send_events(design, &l, &s, seen, counted)).ok()?;
|
||||
// own thread is slow to see the end of the stream (#7226). The connection's own thread
|
||||
// leaves it too, so a closed connection stops counting at once (#8315).
|
||||
std::thread::Builder::new().stack_size(64 * 1024).spawn(move || send_events(design, &l, &s, seen, watch_seat)).ok()?;
|
||||
let sent = send(&mut &lines.socket, reply);
|
||||
drop(first);
|
||||
Some((Subscription { lines, stop }, sent))
|
||||
Some((Subscription { lines, stop, seat }, sent))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,6 +482,9 @@ fn design_of(reply: &Value) -> Option<(String, u64)> {
|
||||
impl Drop for Subscription {
|
||||
fn drop(&mut self) {
|
||||
self.stop.store(true, Ordering::Relaxed);
|
||||
// The seat on the watch goes now: the connection is over, and nothing counts it any more
|
||||
// (#8315).
|
||||
self.seat.release();
|
||||
// The socket closes now, not when the thread next looks; a line blocked on a client that
|
||||
// stopped reading ends too.
|
||||
let _ = self.lines.socket.shutdown(std::net::Shutdown::Both);
|
||||
@@ -461,10 +492,10 @@ impl Drop for Subscription {
|
||||
}
|
||||
|
||||
/// The `design.changed` lines of a subscribed connection, each time the design differs from the
|
||||
/// last one it was told of (`seen`), until `stop`. Owns the connection's seat on the watch
|
||||
/// (`counted`), so the seat leaves exactly when this thread does: on `stop`, or on the first
|
||||
/// write a closed client refuses (#7226).
|
||||
fn send_events(design: &DesignWatch, lines: &Lines, stop: &AtomicBool, mut seen: (String, u64), _counted: Subscriber) {
|
||||
/// last one it was told of (`seen`), until `stop`. Holds the connection's seat on the watch
|
||||
/// (`seat`), which it leaves when the thread ends: on `stop`, or on the first write a closed
|
||||
/// client refuses (#7226).
|
||||
fn send_events(design: &DesignWatch, lines: &Lines, stop: &AtomicBool, mut seen: (String, u64), seat: Arc<Seat>) {
|
||||
while !stop.load(Ordering::Relaxed) {
|
||||
let Some(now) = design.wait(&seen, stop, Duration::from_secs(1)).filter(|now| *now != seen) else { continue };
|
||||
if lines.send(&json!({"event": "design.changed", "params": {"document_id": now.0, "revision": now.1}})).is_err() {
|
||||
@@ -473,6 +504,17 @@ fn send_events(design: &DesignWatch, lines: &Lines, stop: &AtomicBool, mut seen:
|
||||
seen = now;
|
||||
std::thread::sleep(EVENT_GAP);
|
||||
}
|
||||
// The client is gone: it is not counted on the watch any more, whatever the connection's own
|
||||
// thread still has to notice (#8315).
|
||||
seat.release();
|
||||
}
|
||||
|
||||
/// What this app's control channel does beyond the methods every version has, for a client to
|
||||
/// find out before it relies on it (an older app answers `control.capabilities` with "unknown
|
||||
/// method"). `param_check`: the levels `engine.execute`, `engine.batch` and `engine.script` take
|
||||
/// as a request's own parameter check (#9184).
|
||||
fn capabilities() -> Value {
|
||||
json!({"param_check": solidcraft_engine::schema::ParamCheck::ALL.map(|l| l.name())})
|
||||
}
|
||||
|
||||
/// Write `reply` on the connection: through its subscription once it has one.
|
||||
@@ -535,15 +577,20 @@ fn serve_with(
|
||||
let id = msg.get("id").cloned().unwrap_or(Value::Null);
|
||||
let method = msg.get("method").and_then(Value::as_str).unwrap_or("").to_string();
|
||||
let params = msg.get("params").cloned().unwrap_or(json!({}));
|
||||
// A request that timed out may have finished since (#1618). `control.running` only
|
||||
// looks, so it leaves that reply where it is.
|
||||
let late = pending.as_ref().filter(|_| method != "control.running").and_then(|p| match p.reply.try_recv() {
|
||||
// A request that timed out may have finished since (#1618). `control.running` and
|
||||
// `control.capabilities` only look, so they leave that reply where it is.
|
||||
let late = pending.as_ref().filter(|_| !matches!(method.as_str(), "control.running" | "control.capabilities")).and_then(|p| match p
|
||||
.reply
|
||||
.try_recv()
|
||||
{
|
||||
Ok(reply) => Some(reply),
|
||||
Err(TryRecvError::Disconnected) => Some(json!({"ok": false, "error": "the app ended the request without a reply"})),
|
||||
Err(TryRecvError::Empty) => None,
|
||||
});
|
||||
let mut r = if method == "control.running" {
|
||||
json!({"ok": true, "result": running.result(connection)})
|
||||
} else if method == "control.capabilities" {
|
||||
json!({"ok": true, "result": capabilities()})
|
||||
} else if method == "control.pending" {
|
||||
match (pending.take(), late) {
|
||||
(None, _) => json!({"ok": true, "result": {"pending": null}}),
|
||||
@@ -750,6 +797,9 @@ mod tests {
|
||||
let mut watcher = open();
|
||||
let (r, rows) = running(&mut watcher, &|_| true);
|
||||
assert!(r["ok"] == true && rows.is_empty(), "idle: {r}");
|
||||
// What the app's control channel does beyond the methods every version has (#9184).
|
||||
let r = watcher(json!({"id": 0, "method": "control.capabilities", "token": token}));
|
||||
assert_eq!((&r["ok"], &r["result"]["param_check"]), (&json!(true), &json!(["off", "warn", "strict"])), "{r}");
|
||||
|
||||
let mut export = open();
|
||||
let path = "/private/part.step";
|
||||
@@ -781,6 +831,9 @@ mod tests {
|
||||
let own: Vec<&Value> = r["result"]["running"].as_array().unwrap().iter().filter(|row| row["self"] == true).collect();
|
||||
assert_eq!(own.len(), 1, "{r}");
|
||||
assert_eq!(own[0]["command"], "file.export", "{r}");
|
||||
// So may it ask what the app can do: answered at once, not refused as busy.
|
||||
let r = export(json!({"id": 8, "method": "control.capabilities"}));
|
||||
assert_eq!(r["result"]["param_check"], json!(["off", "warn", "strict"]), "{r}");
|
||||
|
||||
gate_tx.send(()).unwrap();
|
||||
assert_eq!(queued.join().unwrap()["result"], "engine.batch");
|
||||
@@ -886,6 +939,58 @@ mod tests {
|
||||
assert!(!WATCH.subscribed());
|
||||
}
|
||||
|
||||
/// #8315: a closed connection leaves the watch at once. The seat of a subscribed connection
|
||||
/// goes when the connection's own thread sees the end of the stream, not only when the
|
||||
/// events thread notices: that thread waits for the design to move, so a connection that
|
||||
/// closed while the design stood still kept the watch counting it for a second or more.
|
||||
#[test]
|
||||
fn a_closed_connection_leaves_the_watch_at_once() {
|
||||
static RUNNING: Running = Running::new();
|
||||
static WATCH: DesignWatch = DesignWatch::new();
|
||||
let token = "0123456789abcdef0123456789abcdef";
|
||||
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
||||
let addr = listener.local_addr().unwrap();
|
||||
let (tx, rx) = channel::<ControlRequest>();
|
||||
// The window names the design once and then leaves it alone: nothing moves it, so the
|
||||
// events thread has nothing to write and only the end of the connection can retire it.
|
||||
std::thread::spawn(move || {
|
||||
for req in rx {
|
||||
if req.method == "control.subscribe" {
|
||||
WATCH.publish("d-1", 3);
|
||||
let _ = req.reply.send(json!({"ok": true, "result": {"document_id": "d-1", "revision": 3}}));
|
||||
} else {
|
||||
let _ = req.reply.send(json!({"ok": true, "result": req.method}));
|
||||
}
|
||||
}
|
||||
});
|
||||
std::thread::spawn(move || {
|
||||
for stream in listener.incoming().flatten() {
|
||||
let tx = tx.clone();
|
||||
std::thread::spawn(move || serve_with(stream, token, tx, egui::Context::default(), false, WAITS, &RUNNING, &WATCH));
|
||||
}
|
||||
});
|
||||
let s = TcpStream::connect(addr).unwrap();
|
||||
s.set_read_timeout(Some(Duration::from_secs(10))).unwrap();
|
||||
let mut out = s.try_clone().unwrap();
|
||||
let mut lines = BufReader::new(s);
|
||||
writeln!(out, "{}", json!({"id": 1, "method": "control.subscribe", "token": token})).unwrap();
|
||||
let mut l = String::new();
|
||||
lines.read_line(&mut l).unwrap();
|
||||
let reply: Value = serde_json::from_str(&l).unwrap();
|
||||
assert!(reply["ok"] == true, "{reply}");
|
||||
assert!(WATCH.subscribed(), "the connection is subscribed");
|
||||
// Let the events thread settle into its wait: the design stands still, so it has nothing
|
||||
// to write, and only the end of the connection can retire it.
|
||||
std::thread::sleep(Duration::from_millis(200));
|
||||
// The client goes away without asking anything else.
|
||||
drop((out, lines));
|
||||
let deadline = Instant::now() + Duration::from_millis(400);
|
||||
while WATCH.subscribed() && Instant::now() < deadline {
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
assert!(!WATCH.subscribed(), "a closed connection is not counted on the watch");
|
||||
}
|
||||
|
||||
/// A timed-out request that only reads is not said to "still apply", nor is one that only
|
||||
/// writes a file (an export, #1989); a change is, by name.
|
||||
#[test]
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
//! Linux: the desktop's dark or light preference, for Theme: System (#7944).
|
||||
//!
|
||||
//! The window toolkit does not pass it on everywhere: on GNOME (Wayland, or X11 through XWayland)
|
||||
//! the window never learns it, nor when it changes, so the app kept its colours. This reads the
|
||||
//! freedesktop setting through the XDG Desktop Portal's Settings interface on the session bus
|
||||
//! (`org.freedesktop.appearance color-scheme`, then GNOME's `color-scheme` and `gtk-theme`), the
|
||||
//! same setting other applications follow, and inside a Flatpak too. It runs on a thread of its
|
||||
//! own: the first reading, then the portal's `SettingChanged` signal; where the signal can't be
|
||||
//! had, a reading every few seconds. Without a portal it asks `gsettings` instead, on the same
|
||||
//! thread. The window reads the last answer with an atomic load
|
||||
//! (`solidcraft_ui_egui::Services::desktop_dark`), and the decision from the raw values is
|
||||
//! `solidcraft_ui_egui::prefs::desktop_prefers_dark`.
|
||||
|
||||
use std::io::Read;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicU8, Ordering};
|
||||
use std::time::Duration;
|
||||
|
||||
use zbus::zvariant::{OwnedValue, Value};
|
||||
|
||||
const UNKNOWN: u8 = 0;
|
||||
const DARK: u8 = 1;
|
||||
const LIGHT: u8 = 2;
|
||||
|
||||
/// How often to read again where the portal's change signal is not available.
|
||||
const POLL: Duration = Duration::from_secs(5);
|
||||
/// How long one `gsettings` reading may take before it is given up.
|
||||
const GSETTINGS_TIMEOUT: Duration = Duration::from_secs(2);
|
||||
|
||||
const PORTAL: &str = "org.freedesktop.portal.Desktop";
|
||||
const PORTAL_PATH: &str = "/org/freedesktop/portal/desktop";
|
||||
const SETTINGS: &str = "org.freedesktop.portal.Settings";
|
||||
const APPEARANCE: &str = "org.freedesktop.appearance";
|
||||
const GNOME: &str = "org.gnome.desktop.interface";
|
||||
|
||||
/// Start following the desktop's preference; the closure answers the latest reading (`None`
|
||||
/// until there is one, or when the desktop says nothing).
|
||||
pub fn start(ctx: &egui::Context) -> Box<dyn Fn() -> Option<bool>> {
|
||||
let state = Arc::new(AtomicU8::new(UNKNOWN));
|
||||
let (thread_state, ctx) = (state.clone(), ctx.clone());
|
||||
if let Err(e) = std::thread::Builder::new().name("desktop-theme".into()).spawn(move || follow(&thread_state, &ctx)) {
|
||||
log::warn!("desktop theme: no thread to follow it: {e}");
|
||||
}
|
||||
Box::new(move || match state.load(Ordering::Relaxed) {
|
||||
DARK => Some(true),
|
||||
LIGHT => Some(false),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Keep `state` on the desktop's preference, asking for a frame whenever it changes.
|
||||
fn follow(state: &AtomicU8, ctx: &egui::Context) {
|
||||
let publish = |dark: Option<bool>| {
|
||||
let code = match dark {
|
||||
Some(true) => DARK,
|
||||
Some(false) => LIGHT,
|
||||
None => UNKNOWN,
|
||||
};
|
||||
if state.swap(code, Ordering::Relaxed) != code {
|
||||
ctx.request_repaint();
|
||||
}
|
||||
};
|
||||
let portal = match portal() {
|
||||
Ok(p) => Some(p),
|
||||
Err(e) => {
|
||||
log::info!("desktop theme: no settings portal ({e}); asking gsettings");
|
||||
None
|
||||
}
|
||||
};
|
||||
// The portal first; gsettings where there is none or it says nothing (its backend missing).
|
||||
let read = |portal: Option<&zbus::blocking::Proxy<'static>>| portal.and_then(read_portal).or_else(read_gsettings);
|
||||
let from_portal = portal.as_ref().and_then(read_portal);
|
||||
let first = from_portal.or_else(read_gsettings);
|
||||
publish(first);
|
||||
// Wait for the portal's signal only when the portal answers: else the reading is gsettings',
|
||||
// which only a new reading notices.
|
||||
if let Some(p) = portal.as_ref().filter(|_| from_portal.is_some()) {
|
||||
match p.receive_signal("SettingChanged") {
|
||||
Ok(changes) => {
|
||||
for message in changes {
|
||||
if relevant(&message) {
|
||||
publish(read(Some(p)));
|
||||
}
|
||||
}
|
||||
log::info!("desktop theme: the portal's change signal ended; reading every few seconds");
|
||||
}
|
||||
Err(e) => log::info!("desktop theme: no change signal ({e}); reading every few seconds"),
|
||||
}
|
||||
} else if portal.is_none() && first.is_none() && !gsettings_available() {
|
||||
// Neither the portal nor gsettings: nothing to follow; the window toolkit's theme stays.
|
||||
return;
|
||||
}
|
||||
loop {
|
||||
std::thread::sleep(POLL);
|
||||
publish(read(portal.as_ref()));
|
||||
}
|
||||
}
|
||||
|
||||
/// The portal's Settings interface on the session bus.
|
||||
fn portal() -> zbus::Result<zbus::blocking::Proxy<'static>> {
|
||||
let connection = zbus::blocking::Connection::session()?;
|
||||
zbus::blocking::Proxy::new(&connection, PORTAL, PORTAL_PATH, SETTINGS)
|
||||
}
|
||||
|
||||
/// One reading through the portal.
|
||||
fn read_portal(portal: &zbus::blocking::Proxy<'static>) -> Option<bool> {
|
||||
let appearance = read_setting(portal, APPEARANCE, "color-scheme").and_then(|v| as_u32(&v));
|
||||
// The GNOME settings only matter when the freedesktop one has no preference.
|
||||
if matches!(appearance, Some(1 | 2)) {
|
||||
return solidcraft_ui_egui::prefs::desktop_prefers_dark(appearance, None, None);
|
||||
}
|
||||
let gnome = read_setting(portal, GNOME, "color-scheme").and_then(|v| as_string(&v));
|
||||
let gtk_theme = read_setting(portal, GNOME, "gtk-theme").and_then(|v| as_string(&v));
|
||||
solidcraft_ui_egui::prefs::desktop_prefers_dark(appearance, gnome.as_deref(), gtk_theme.as_deref())
|
||||
}
|
||||
|
||||
/// A setting through `ReadOne` (portal version 2), else the older `Read`.
|
||||
fn read_setting(portal: &zbus::blocking::Proxy<'static>, namespace: &str, key: &str) -> Option<OwnedValue> {
|
||||
let one: zbus::Result<OwnedValue> = portal.call("ReadOne", &(namespace, key));
|
||||
one.or_else(|_| -> zbus::Result<OwnedValue> { portal.call("Read", &(namespace, key)) }).ok()
|
||||
}
|
||||
|
||||
/// Whether a `SettingChanged` signal is about a setting the preference is read from.
|
||||
fn relevant(message: &zbus::Message) -> bool {
|
||||
let body = message.body();
|
||||
let Ok((namespace, key, _)) = body.deserialize::<(String, String, OwnedValue)>() else { return false };
|
||||
matches!((namespace.as_str(), key.as_str()), (APPEARANCE, "color-scheme") | (GNOME, "color-scheme" | "gtk-theme"))
|
||||
}
|
||||
|
||||
/// The value inside the variants `Read` wraps it in (a portal answers one or two deep).
|
||||
fn unwrap_variants<'v, 'a>(value: &'v Value<'a>) -> &'v Value<'a> {
|
||||
let mut value = value;
|
||||
for _ in 0..4 {
|
||||
match value {
|
||||
Value::Value(inner) => value = &**inner,
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
fn as_u32(value: &Value<'_>) -> Option<u32> {
|
||||
match unwrap_variants(value) {
|
||||
Value::U32(n) => Some(*n),
|
||||
Value::I32(n) => u32::try_from(*n).ok(),
|
||||
Value::U8(n) => Some(u32::from(*n)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn as_string(value: &Value<'_>) -> Option<String> {
|
||||
match unwrap_variants(value) {
|
||||
Value::Str(s) => Some(s.as_str().to_string()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Without a portal: GNOME's settings through `gsettings` (`None` when it is not there).
|
||||
fn read_gsettings() -> Option<bool> {
|
||||
let gnome = gsettings("color-scheme");
|
||||
let gtk_theme = gsettings("gtk-theme");
|
||||
solidcraft_ui_egui::prefs::desktop_prefers_dark(None, gnome.as_deref(), gtk_theme.as_deref())
|
||||
}
|
||||
|
||||
fn gsettings_available() -> bool {
|
||||
gsettings("gtk-theme").is_some()
|
||||
}
|
||||
|
||||
/// `gsettings get org.gnome.desktop.interface <key>`, its quoted answer, or `None` when the
|
||||
/// program is missing, fails or does not answer in time.
|
||||
fn gsettings(key: &str) -> Option<String> {
|
||||
let mut child = std::process::Command::new("gsettings")
|
||||
.args(["get", GNOME, key])
|
||||
.stdin(std::process::Stdio::null())
|
||||
.stdout(std::process::Stdio::piped())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.spawn()
|
||||
.ok()?;
|
||||
let started = std::time::Instant::now();
|
||||
loop {
|
||||
match child.try_wait() {
|
||||
Ok(Some(status)) if status.success() => break,
|
||||
Ok(None) if started.elapsed() < GSETTINGS_TIMEOUT => std::thread::sleep(Duration::from_millis(20)),
|
||||
_ => {
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut out = String::new();
|
||||
child.stdout.take()?.take(4096).read_to_string(&mut out).ok()?;
|
||||
let value = out.trim().trim_matches('\'').to_string();
|
||||
(!value.is_empty()).then_some(value)
|
||||
}
|
||||
@@ -5,12 +5,25 @@
|
||||
//! for recovery as a forced quit does, and starts again ([`restart`]), and the new start says what
|
||||
//! happened ([`note`]). A device lost again soon after such a restart starts the next one on the
|
||||
//! software renderer, which doesn't depend on the graphics driver.
|
||||
//!
|
||||
//! The old process ends without tearing down its GPU objects ([`end`]): on a lost NVIDIA device
|
||||
//! destroying the window's swap chain busy-waits in the driver and never returns (#9044).
|
||||
|
||||
use crate::startup;
|
||||
|
||||
/// Set on the start after a lost device: when the device was lost (seconds since 1970).
|
||||
pub const LOST_ENV: &str = "SOLIDCRAFT_DEVICE_LOST";
|
||||
|
||||
/// Set on the start after a lost device: why it was lost, as wgpu said it. The old process's
|
||||
/// session journal, which recorded it, is gone by then.
|
||||
pub const REASON_ENV: &str = "SOLIDCRAFT_DEVICE_LOST_REASON";
|
||||
|
||||
/// The longest reason passed on ([`REASON_ENV`]) and shown, in characters.
|
||||
const REASON_CHARS: usize = 300;
|
||||
|
||||
/// How long the process may take to end ([`end`]) before it is aborted.
|
||||
const END_GRACE: std::time::Duration = std::time::Duration::from_secs(3);
|
||||
|
||||
/// A loss this recent (seconds) counts for the start after it: its note, and a second loss
|
||||
/// within it starts on the software renderer. Inherited by later starts, an older stamp is
|
||||
/// ignored.
|
||||
@@ -32,27 +45,54 @@ pub fn restart_on_software(after_recent_loss: bool, cpu_renderer: bool) -> bool
|
||||
after_recent_loss || cpu_renderer
|
||||
}
|
||||
|
||||
/// `reason` on one line, at most [`REASON_CHARS`] long; None when there is nothing to say.
|
||||
pub fn reason(reason: Option<&str>) -> Option<String> {
|
||||
let line = reason?.split_whitespace().collect::<Vec<_>>().join(" ");
|
||||
(!line.is_empty()).then(|| line.chars().take(REASON_CHARS).collect())
|
||||
}
|
||||
|
||||
/// What the start after a lost device tells the user, `software` when it runs on the software
|
||||
/// renderer.
|
||||
pub fn note(software: bool) -> String {
|
||||
/// renderer, with what the driver reported ([`REASON_ENV`]).
|
||||
pub fn note(software: bool, reason: Option<&str>) -> String {
|
||||
let mut note = String::from(
|
||||
"The graphics device was reset (the graphics driver stopped responding), so SolidCraft closed and started again. Unsaved changes were kept for recovery.",
|
||||
);
|
||||
if software {
|
||||
note.push_str(" This start uses software rendering, which doesn't depend on the graphics driver.");
|
||||
}
|
||||
if let Some(reason) = self::reason(reason) {
|
||||
note.push_str(&format!(" The graphics driver reported: {reason}"));
|
||||
}
|
||||
note
|
||||
}
|
||||
|
||||
/// Start SolidCraft again with the same arguments, the loss stamped at `lost_at`, on the software
|
||||
/// renderer when `software`.
|
||||
pub fn restart(software: bool, lost_at: u64) {
|
||||
let Ok(exe) = std::env::current_exe() else { return };
|
||||
/// The command that starts `exe` again with `args`, the loss stamped at `lost_at` and its
|
||||
/// `reason`, on the software renderer when `software`.
|
||||
fn command(
|
||||
exe: std::path::PathBuf,
|
||||
args: impl IntoIterator<Item = std::ffi::OsString>,
|
||||
software: bool,
|
||||
lost_at: u64,
|
||||
reason: &str,
|
||||
) -> std::process::Command {
|
||||
let mut command = std::process::Command::new(exe);
|
||||
command.args(std::env::args_os().skip(1)).env(LOST_ENV, lost_at.to_string());
|
||||
command.args(args).env(LOST_ENV, lost_at.to_string());
|
||||
match self::reason(Some(reason)) {
|
||||
Some(reason) => command.env(REASON_ENV, reason),
|
||||
// Not one inherited from an earlier loss.
|
||||
None => command.env_remove(REASON_ENV),
|
||||
};
|
||||
if software {
|
||||
command.env(startup::RENDERER_ENV, "cpu");
|
||||
}
|
||||
command
|
||||
}
|
||||
|
||||
/// Start SolidCraft again with the same arguments, the loss stamped at `lost_at` and its `reason`,
|
||||
/// on the software renderer when `software`.
|
||||
pub fn restart(software: bool, lost_at: u64, reason: &str) {
|
||||
let Ok(exe) = std::env::current_exe() else { return };
|
||||
let mut command = command(exe, std::env::args_os().skip(1), software, lost_at, reason);
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use std::os::windows::process::CommandExt;
|
||||
@@ -64,6 +104,23 @@ pub fn restart(software: bool, lost_at: u64) {
|
||||
}
|
||||
}
|
||||
|
||||
/// End the process now, without tearing down what is left on the lost device: the window's swap
|
||||
/// chain, the viewport's buffers and pipelines. On NVIDIA's Vulkan driver destroying the swap
|
||||
/// chain of a lost device busy-waits forever, which left the old window frozen at 100% of a core
|
||||
/// beside the new one (#9044). Should the exit itself get stuck in a library's exit handler, the
|
||||
/// process is aborted after [`END_GRACE`].
|
||||
pub fn end() -> ! {
|
||||
let watchdog = std::thread::Builder::new().name("solidcraft-exit".into()).spawn(|| {
|
||||
std::thread::sleep(END_GRACE);
|
||||
eprintln!("SolidCraft graphics: still closing after the device was lost; aborting");
|
||||
std::process::abort();
|
||||
});
|
||||
if let Err(e) = watchdog {
|
||||
log::warn!("graphics: no exit watchdog: {e}");
|
||||
}
|
||||
std::process::exit(0)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
/// Only a recent, well-formed stamp counts: a later start that inherited it says nothing.
|
||||
@@ -84,8 +141,34 @@ mod tests {
|
||||
assert!(!super::restart_on_software(false, false));
|
||||
assert!(super::restart_on_software(true, false));
|
||||
assert!(super::restart_on_software(false, true));
|
||||
assert!(super::note(true).contains("software rendering"));
|
||||
assert!(!super::note(false).contains("software rendering"));
|
||||
assert!(super::note(false).contains("kept for recovery"));
|
||||
assert!(super::note(true, None).contains("software rendering"));
|
||||
assert!(!super::note(false, None).contains("software rendering"));
|
||||
assert!(super::note(false, None).contains("kept for recovery"));
|
||||
}
|
||||
|
||||
/// The start after a loss is told why (#9044): the old process's journal held the reason, and
|
||||
/// it is deleted as that process closes.
|
||||
#[test]
|
||||
fn the_next_start_is_told_why_the_device_was_lost() {
|
||||
let exe = std::path::PathBuf::from("solidcraft");
|
||||
let args = ["--control".into(), "7979".into()];
|
||||
let command = super::command(exe.clone(), args, true, 1_000, "Lost: Device lost\n (vkQueueSubmit)");
|
||||
let env = |command: &std::process::Command, name: &str| {
|
||||
command.get_envs().find(|(k, _)| *k == name).map(|(_, v)| v.map(|v| v.to_string_lossy().into_owned()))
|
||||
};
|
||||
assert_eq!(env(&command, super::LOST_ENV), Some(Some("1000".into())));
|
||||
assert_eq!(env(&command, super::REASON_ENV), Some(Some("Lost: Device lost (vkQueueSubmit)".into())), "on one line");
|
||||
assert_eq!(env(&command, crate::startup::RENDERER_ENV), Some(Some("cpu".into())));
|
||||
assert_eq!(command.get_args().collect::<Vec<_>>(), ["--control", "7979"]);
|
||||
// No reason: none inherited from an earlier loss either.
|
||||
let command = super::command(exe, Vec::new(), false, 1_000, " ");
|
||||
assert_eq!(env(&command, super::REASON_ENV), Some(None));
|
||||
assert_eq!(env(&command, crate::startup::RENDERER_ENV), None);
|
||||
|
||||
let note = super::note(false, Some("Lost: Device lost"));
|
||||
assert!(note.ends_with("The graphics driver reported: Lost: Device lost"), "{note}");
|
||||
assert!(!super::note(false, Some(" \n ")).contains("reported"));
|
||||
let long = "x".repeat(1_000);
|
||||
assert_eq!(super::reason(Some(&long)).map(|r| r.chars().count()), Some(300));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
mod app_icon;
|
||||
mod come_forward;
|
||||
mod control_server;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod desktop_theme;
|
||||
mod device_lost;
|
||||
#[cfg(target_os = "windows")]
|
||||
mod native_crash;
|
||||
@@ -97,6 +99,86 @@ struct App {
|
||||
nav_bridge: nav_bridge::NavBridge,
|
||||
/// Where the next file dialog opens: it follows the open design (#7756).
|
||||
dialog_folder: DialogFolder,
|
||||
/// Settings go to `app.ron` in the frame they change (#8275).
|
||||
prefs_writer: PrefsWriter,
|
||||
}
|
||||
|
||||
/// Settings written to the settings file soon after they change (#8275). eframe saves them
|
||||
/// only every 30 s and when the window closes normally, so a change was lost whenever the app
|
||||
/// did not get that far: ended from the Task Manager, stopped by a sign-out or shutdown, or
|
||||
/// crashed or hung in the graphics driver on the way out.
|
||||
///
|
||||
/// Some settings change continuously (a panel's width while its edge is dragged), so the file
|
||||
/// is written at most once per [`PrefsWriter::INTERVAL`], and a change made in between is written
|
||||
/// when that interval ends.
|
||||
#[derive(Default)]
|
||||
struct PrefsWriter {
|
||||
/// The settings written (or read at start) last.
|
||||
written: Option<String>,
|
||||
/// The previous frame had input that can change settings: what it changed shows in this
|
||||
/// frame's settings.
|
||||
input_before: bool,
|
||||
/// When the settings were last written by this writer.
|
||||
last_write: Option<std::time::Instant>,
|
||||
/// A change waits until then to be written.
|
||||
pending_until: Option<std::time::Instant>,
|
||||
}
|
||||
|
||||
impl PrefsWriter {
|
||||
/// The least time between two writes of the settings file.
|
||||
const INTERVAL: std::time::Duration = std::time::Duration::from_secs(1);
|
||||
|
||||
/// The settings as they were read at start: they are on disk already.
|
||||
fn read(prefs: String) -> Self {
|
||||
Self { written: Some(prefs), ..Self::default() }
|
||||
}
|
||||
|
||||
/// Whether this frame's settings are worth comparing: input that can change them came in this
|
||||
/// frame or the one before, or a waiting change's time has come. Pointer motion alone isn't
|
||||
/// such input; eframe's own save still catches anything else.
|
||||
fn due(&mut self, input: bool, now: std::time::Instant) -> bool {
|
||||
let due = input || self.input_before || self.pending_until.is_some_and(|at| now >= at);
|
||||
self.input_before = input;
|
||||
due
|
||||
}
|
||||
|
||||
/// Write `prefs` and flush them to disk if they differ from the settings written last and the
|
||||
/// last write is at least [`Self::INTERVAL`] old. Returns how long a change waits otherwise:
|
||||
/// the caller asks for a frame then, so an idle app still writes it.
|
||||
fn store(&mut self, storage: &mut dyn eframe::Storage, prefs: String, now: std::time::Instant) -> Option<std::time::Duration> {
|
||||
if self.written.as_deref() == Some(prefs.as_str()) {
|
||||
self.pending_until = None;
|
||||
return None;
|
||||
}
|
||||
if let Some(wait) = self.last_write.map(|at| Self::INTERVAL.saturating_sub(now.saturating_duration_since(at))).filter(|w| !w.is_zero()) {
|
||||
self.pending_until = Some(now + wait);
|
||||
return Some(wait);
|
||||
}
|
||||
storage.set_string(solidcraft_ui_egui::prefs::STORAGE_KEY, prefs.clone());
|
||||
storage.flush();
|
||||
self.written = Some(prefs);
|
||||
self.last_write = Some(now);
|
||||
self.pending_until = None;
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Input that can change a setting: a click, a key, typed or pasted text, a wheel or a pinch.
|
||||
/// Pointer motion, which comes every frame while the mouse moves, cannot by itself.
|
||||
fn changes_settings(event: &egui::Event) -> bool {
|
||||
matches!(
|
||||
event,
|
||||
egui::Event::PointerButton { .. }
|
||||
| egui::Event::Key { .. }
|
||||
| egui::Event::Text(_)
|
||||
| egui::Event::Paste(_)
|
||||
| egui::Event::Cut
|
||||
| egui::Event::Ime(_)
|
||||
| egui::Event::MouseWheel { .. }
|
||||
| egui::Event::Zoom(_)
|
||||
| egui::Event::Rotate(_)
|
||||
| egui::Event::AccessKitActionRequest(_)
|
||||
)
|
||||
}
|
||||
|
||||
impl eframe::App for App {
|
||||
@@ -184,11 +266,21 @@ impl eframe::App for App {
|
||||
solidcraft_ui_egui::space_mouse::buttons_hook(&mut self.solve, ctx, self.space_mouse.buttons(), raw);
|
||||
self.solve.raw_input_hook(raw);
|
||||
}
|
||||
fn ui(&mut self, ui: &mut egui::Ui, _frame: &mut eframe::Frame) {
|
||||
fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
|
||||
content_ui(&mut self.solve, ui);
|
||||
// After the frame's UI, so a setting changed in it (Preferences' OK) is written now.
|
||||
let now = std::time::Instant::now();
|
||||
if self.prefs_writer.due(ui.input(|i| i.events.iter().any(changes_settings)), now)
|
||||
&& let Some(storage) = frame.storage_mut()
|
||||
&& let Some(wait) = self.prefs_writer.store(storage, self.solve.prefs(), now)
|
||||
{
|
||||
ui.ctx().request_repaint_after(wait);
|
||||
}
|
||||
}
|
||||
fn save(&mut self, storage: &mut dyn eframe::Storage) {
|
||||
storage.set_string(solidcraft_ui_egui::prefs::STORAGE_KEY, self.solve.prefs());
|
||||
let prefs = self.solve.prefs();
|
||||
storage.set_string(solidcraft_ui_egui::prefs::STORAGE_KEY, prefs.clone());
|
||||
self.prefs_writer.written = Some(prefs);
|
||||
}
|
||||
fn on_exit(&mut self) {
|
||||
// The agent chat's agent and everything it started end with the app.
|
||||
@@ -202,13 +294,29 @@ impl eframe::App for App {
|
||||
}
|
||||
solidcraft_ui_egui::recovery_ui::close(&mut self.solve);
|
||||
solidcraft_ui_egui::open_elsewhere::close(&mut self.solve);
|
||||
// Before a restart below starts the next instance, which would otherwise get nothing from
|
||||
// the 3D mouse driver (`solidcraft_3dx_client::stop`).
|
||||
// Before a restart (`Drop for App`) starts the next instance, which would otherwise get
|
||||
// nothing from the 3D mouse driver (`solidcraft_3dx_client::stop`).
|
||||
#[cfg(target_os = "macos")]
|
||||
solidcraft_3dx_client::stop();
|
||||
solidcraft_engine::crash::end_session();
|
||||
if let Some(lost_at) = self.gpu.as_ref().and_then(|g| g.lost_at) {
|
||||
device_lost::restart(self.gpu.as_ref().is_some_and(|g| g.restart_on_software), lost_at);
|
||||
// The next start (after a lost device, or into an update) begins once the app is dropped
|
||||
// (`Drop for App`), when the settings are on disk.
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for App {
|
||||
/// eframe drops its settings storage first, which waits for `app.ron` to be written, then the
|
||||
/// app, then the window and its GPU surface. So the next start begins here: started from
|
||||
/// `on_exit`, it read `app.ron` while the old process was still writing it, found it
|
||||
/// unreadable and moved it aside, resetting every setting (#9044).
|
||||
fn drop(&mut self) {
|
||||
if let Some(gpu) = &self.gpu
|
||||
&& let Some(lost_at) = gpu.lost_at
|
||||
{
|
||||
device_lost::restart(gpu.restart_on_software, lost_at, &gpu.reason);
|
||||
// The window's GPU surface is still to be dropped, and on a lost device that may
|
||||
// never return (#9044).
|
||||
device_lost::end();
|
||||
}
|
||||
// An update asked to restart into the new version or to run its installer.
|
||||
if let Some((program, args)) = solidcraft_ui_egui::update::take_launch(&mut self.solve) {
|
||||
@@ -236,6 +344,8 @@ struct LostWatch {
|
||||
restart_on_software: bool,
|
||||
/// When the loss was seen: the app is closing to start again.
|
||||
lost_at: Option<u64>,
|
||||
/// Why, as wgpu said it: passed to the next start ([`device_lost::REASON_ENV`]).
|
||||
reason: String,
|
||||
}
|
||||
|
||||
impl App {
|
||||
@@ -249,6 +359,7 @@ impl App {
|
||||
eprintln!("SolidCraft graphics: the device was lost ({reason}); starting again");
|
||||
solidcraft_engine::crash::phase(&format!("graphics device lost: {reason}"));
|
||||
gpu.lost_at = Some(device_lost::now_secs());
|
||||
gpu.reason = reason;
|
||||
self.solve.quit_requested = true;
|
||||
}
|
||||
}
|
||||
@@ -422,6 +533,12 @@ fn services(cc: &eframe::CreationContext<'_>, folder: &DialogFolder) -> Services
|
||||
graphics_adapters: Vec::new(),
|
||||
graphics_path: graphics_path().map(|p| p.to_string_lossy().to_string()),
|
||||
window_system: window_system_now(),
|
||||
// Linux: the desktop's dark or light setting, which the window is not told on every
|
||||
// desktop (#7944). Windows and macOS: the window's own theme.
|
||||
#[cfg(target_os = "linux")]
|
||||
desktop_dark: Some(desktop_theme::start(&cc.egui_ctx)),
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
desktop_dark: None,
|
||||
http_get: Some(std::sync::Arc::new(http_get)),
|
||||
http_download: Some(std::sync::Arc::new(http_download)),
|
||||
// Already an installed app: only the browser build offers to install.
|
||||
@@ -701,6 +818,24 @@ fn msaa() -> Option<u16> {
|
||||
/// (`solidcraft_ui_egui::titlebar`). macOS keeps its traffic lights over the integrated bar.
|
||||
const CUSTOM_TITLEBAR: bool = !cfg!(target_os = "macos");
|
||||
|
||||
/// Linux: the window manager's own decorations (server-side, or the compositor's frame) can be
|
||||
/// asked for instead of the application bar ([`titlebar_choice`]). Elsewhere always `true`.
|
||||
fn app_titlebar_wanted() -> bool {
|
||||
if !cfg!(all(unix, not(target_os = "macos"))) {
|
||||
return true;
|
||||
}
|
||||
let setting = graphics().and_then(|v| v.get("titlebar").and_then(serde_json::Value::as_str).map(str::to_string));
|
||||
titlebar_choice(solidcraft_engine::geom::env::var("TITLEBAR").as_deref(), setting.as_deref())
|
||||
}
|
||||
|
||||
/// Linux: whether the application bar is the title bar. `SOLIDCRAFT_TITLEBAR` (else
|
||||
/// `graphics.json`'s `titlebar`) set to `system` gives the window the desktop's own title bar and
|
||||
/// buttons; `app` (or anything else, or nothing) keeps the application bar as the title bar.
|
||||
fn titlebar_choice(env: Option<&str>, setting: Option<&str>) -> bool {
|
||||
let choice = env.map(str::trim).filter(|v| !v.is_empty()).or(setting.map(str::trim));
|
||||
!choice.is_some_and(|v| v.eq_ignore_ascii_case("system"))
|
||||
}
|
||||
|
||||
const DEPTH_BITS: u8 = 24;
|
||||
/// A 32-bit float depth buffer, drawn with reversed depth (1 near, 0 far) so its precision follows
|
||||
/// the distance from the eye (#1434). Only where every adapter offers it with a stencil
|
||||
@@ -750,6 +885,16 @@ fn main() -> eframe::Result {
|
||||
#[cfg(target_os = "macos")]
|
||||
objc2_foundation::NSProcessInfo::processInfo().setProcessName(objc2_foundation::ns_string!("SolidCraft"));
|
||||
mark("main");
|
||||
// On OCLP-patched Macs, wgpu picks a Metal Shading Language standard that the system's
|
||||
// compiler refuses (`invalid value 'metal3.2'`), because the patched OS reports a newer
|
||||
// macOS version than the GPU's Metal compiler supports. Re-launching with
|
||||
// SYSTEM_VERSION_COMPAT=1 makes the OS report the real (older) version so wgpu selects
|
||||
// a standard the compiler accepts. The variable must be set before the process starts, so
|
||||
// we detect OCLP here and re-exec immediately, before any macOS framework call (#3080, #4605).
|
||||
#[cfg(target_os = "macos")]
|
||||
if let Err(e) = startup::relaunch_with_version_compat() {
|
||||
log::warn!("startup: OCLP check failed (continuing normally): {e}");
|
||||
}
|
||||
// Validate before legacy adoption, crash markers or any user preference read.
|
||||
let settings = settings_dir().map_err(|error| eframe::Error::AppCreation(error.into()))?;
|
||||
if std::env::var_os("SOLIDCRAFT_SETTINGS_DIR").is_none() {
|
||||
@@ -821,7 +966,11 @@ fn main() -> eframe::Result {
|
||||
// The launch before this one closed because its graphics device was lost (`App::watch_device`).
|
||||
let after_loss = device_lost::recent(std::env::var(device_lost::LOST_ENV).ok().as_deref(), device_lost::now_secs());
|
||||
if after_loss {
|
||||
notes.push(device_lost::note(cpu_renderer));
|
||||
let reason = std::env::var(device_lost::REASON_ENV).ok();
|
||||
if let Some(reason) = device_lost::reason(reason.as_deref()) {
|
||||
log::warn!("graphics: the last launch lost its device ({reason})");
|
||||
}
|
||||
notes.push(device_lost::note(cpu_renderer, reason.as_deref()));
|
||||
}
|
||||
if safe_mode {
|
||||
notes.push("Safe mode: default settings (yours are kept for the next normal start), no recovery offer, software rendering.".into());
|
||||
@@ -857,7 +1006,7 @@ fn main() -> eframe::Result {
|
||||
eframe::egui_wgpu::WgpuSetup::CreateNew(setup) => setup.instance_descriptor.backends,
|
||||
_ => eframe::wgpu::Backends::all(),
|
||||
};
|
||||
let custom_titlebar = CUSTOM_TITLEBAR && !startup::system_title_bar(cfg!(target_os = "windows"), started);
|
||||
let custom_titlebar = CUSTOM_TITLEBAR && app_titlebar_wanted() && !startup::system_title_bar(cfg!(target_os = "windows"), started);
|
||||
eframe::egui_wgpu::set_startup_hook(startup_step);
|
||||
solidcraft_engine::crash::phase("window");
|
||||
let options = eframe::NativeOptions {
|
||||
@@ -961,6 +1110,7 @@ fn main() -> eframe::Result {
|
||||
lost: rs.device_lost.clone(),
|
||||
restart_on_software: device_lost::restart_on_software(after_loss, cpu_renderer),
|
||||
lost_at: None,
|
||||
reason: String::new(),
|
||||
});
|
||||
if !safe_mode {
|
||||
app.preferences.graphics_adapter =
|
||||
@@ -976,6 +1126,12 @@ fn main() -> eframe::Result {
|
||||
})
|
||||
.collect();
|
||||
let info = rs.adapter.get_info();
|
||||
if !app.preferences.graphics_adapter.is_empty() && !info.name.eq_ignore_ascii_case(app.preferences.graphics_adapter.as_str()) {
|
||||
eprintln!(
|
||||
"SolidCraft graphics: preferred adapter {:?} was not used; using {:?} instead",
|
||||
app.preferences.graphics_adapter, info.name
|
||||
);
|
||||
}
|
||||
let samples = scene_msaa_request(saved_samples);
|
||||
let supported = scene_sample_choices(depth_bits, STENCIL_BITS, |depth| {
|
||||
eframe::egui_wgpu::supported_msaa_samples(&rs.adapter, &rs.device, rs.target_format, depth)
|
||||
@@ -1016,6 +1172,10 @@ fn main() -> eframe::Result {
|
||||
app.session.doc_mut().name = "Sample Plate".into();
|
||||
app.session.mark_saved();
|
||||
app.session.undo.clear();
|
||||
// Built straight into the session, so nothing asked for a fit: frame it at the
|
||||
// home view as any opened design is (#9195). The fit waits for the first layout.
|
||||
app.cam.set_view(solidcraft_engine::render::StandardView::Iso);
|
||||
app.fit_view();
|
||||
}
|
||||
// Lock files next to open designs: a design open on another computer says so (#5467),
|
||||
// the files given at launch included.
|
||||
@@ -1076,6 +1236,8 @@ fn main() -> eframe::Result {
|
||||
mark("app created");
|
||||
solidcraft_engine::crash::phase("first frame");
|
||||
Ok(Box::new(App {
|
||||
// Before `app` moves: the settings as read, already on disk.
|
||||
prefs_writer: PrefsWriter::read(app.prefs()),
|
||||
solve: app,
|
||||
starting,
|
||||
frames: 0,
|
||||
@@ -1099,12 +1261,13 @@ fn main() -> eframe::Result {
|
||||
}
|
||||
|
||||
/// egui-wgpu is about to start a step of getting the graphics device and the window's surface up:
|
||||
/// the crash journal keeps it, and the adapter once it is picked.
|
||||
/// the crash journal keeps it until the app runs (a window opened later goes through the same
|
||||
/// steps), and the adapter once it is picked.
|
||||
fn startup_step(step: &'static str, detail: &str) {
|
||||
if step == eframe::egui_wgpu::STEP_ADAPTER_CHOSEN {
|
||||
solidcraft_engine::crash::set_environment(&format!("Renderer: {detail}"));
|
||||
}
|
||||
solidcraft_engine::crash::phase(step);
|
||||
solidcraft_engine::crash::startup_step(step);
|
||||
}
|
||||
|
||||
/// The renderer settings: with `cpu`, the software adapter (WARP, lavapipe, llvmpipe). The
|
||||
@@ -1266,6 +1429,148 @@ mod backend_tests {
|
||||
assert!(!prefer_x11(true, true, Some("GNOME"), over(Some("wayland"))));
|
||||
assert!(prefer_x11(true, true, Some("niri"), over(Some("x11"))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_desktops_title_bar_only_when_asked_for() {
|
||||
use super::titlebar_choice;
|
||||
// Nothing set: the application bar is the title bar, as before.
|
||||
assert!(titlebar_choice(None, None));
|
||||
// graphics.json's `titlebar`.
|
||||
assert!(!titlebar_choice(None, Some("system")));
|
||||
assert!(titlebar_choice(None, Some("app")));
|
||||
// SOLIDCRAFT_TITLEBAR wins over the file; empty counts as unset; case and spaces don't matter.
|
||||
assert!(!titlebar_choice(Some(" System "), Some("app")));
|
||||
assert!(titlebar_choice(Some("app"), Some("system")));
|
||||
assert!(!titlebar_choice(Some(""), Some("system")));
|
||||
// Anything unknown keeps the application bar.
|
||||
assert!(titlebar_choice(Some("ssd"), None));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod prefs_writer_tests {
|
||||
use super::PrefsWriter;
|
||||
use solidcraft_ui_egui::prefs::{NavigatorStyle, STORAGE_KEY};
|
||||
use std::collections::HashMap;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
/// eframe's settings file: what was flushed to disk is what the next start reads.
|
||||
#[derive(Default)]
|
||||
struct Disk {
|
||||
pending: HashMap<String, String>,
|
||||
flushed: HashMap<String, String>,
|
||||
flushes: usize,
|
||||
}
|
||||
|
||||
impl eframe::Storage for Disk {
|
||||
fn get_string(&self, key: &str) -> Option<String> {
|
||||
self.pending.get(key).cloned()
|
||||
}
|
||||
fn set_string(&mut self, key: &str, value: String) {
|
||||
self.pending.insert(key.into(), value);
|
||||
}
|
||||
fn remove_string(&mut self, key: &str) {
|
||||
self.pending.remove(key);
|
||||
}
|
||||
fn flush(&mut self) {
|
||||
self.flushed = self.pending.clone();
|
||||
self.flushes += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn new_app() -> solidcraft_ui_egui::SolveApp {
|
||||
solidcraft_ui_egui::SolveApp::new(solidcraft_engine::Session::default(), solidcraft_ui_egui::Services::default())
|
||||
}
|
||||
|
||||
/// #8275: Preferences' View navigator and Display quality, changed and confirmed, are on disk
|
||||
/// in that frame, so the next start has them even when this one never closes normally (ended
|
||||
/// from the Task Manager, a sign-out, a hang or crash in the graphics driver on the way out).
|
||||
#[test]
|
||||
fn changed_settings_reach_the_disk_in_the_frame_they_change() {
|
||||
let mut app = new_app();
|
||||
let mut disk = Disk::default();
|
||||
let mut writer = PrefsWriter::read(app.prefs());
|
||||
let now = Instant::now();
|
||||
assert_eq!(writer.store(&mut disk, app.prefs(), now), None);
|
||||
assert_eq!(disk.flushes, 0, "the settings read at start are not written again");
|
||||
app.preferences.navigator_style = NavigatorStyle::Cube;
|
||||
app.preferences.display_quality = "fine".into();
|
||||
assert!(writer.due(true, now), "a frame with input is checked");
|
||||
assert_eq!(writer.store(&mut disk, app.prefs(), now), None);
|
||||
assert_eq!(disk.flushes, 1, "flushed at once, not left for eframe's next save");
|
||||
assert_eq!(writer.store(&mut disk, app.prefs(), now + Duration::from_secs(5)), None);
|
||||
assert_eq!(disk.flushes, 1, "unchanged settings are not written again");
|
||||
|
||||
// The next start reads them.
|
||||
let mut next = new_app();
|
||||
let stored = solidcraft_ui_egui::prefs::stored(|k| disk.flushed.get(k).cloned()).expect("settings on disk");
|
||||
next.load_prefs(&stored);
|
||||
assert_eq!(next.preferences.navigator_style, NavigatorStyle::Cube);
|
||||
assert_eq!(next.preferences.display_quality, "fine");
|
||||
assert!(disk.flushed.contains_key(STORAGE_KEY));
|
||||
}
|
||||
|
||||
/// A frame without input is checked only right after one with input (whose clicks the UI
|
||||
/// handled in that frame); after that, idle frames cost nothing. Pointer motion, which comes
|
||||
/// every frame while the mouse moves, doesn't count as input.
|
||||
#[test]
|
||||
fn frames_are_checked_with_input_and_once_after_it() {
|
||||
let now = Instant::now();
|
||||
let mut writer = PrefsWriter::default();
|
||||
assert!(!writer.due(false, now));
|
||||
assert!(writer.due(true, now));
|
||||
assert!(writer.due(false, now), "the frame after input");
|
||||
assert!(!writer.due(false, now));
|
||||
|
||||
let click = egui::Event::PointerButton {
|
||||
pos: egui::Pos2::ZERO,
|
||||
button: egui::PointerButton::Primary,
|
||||
pressed: false,
|
||||
modifiers: egui::Modifiers::NONE,
|
||||
};
|
||||
assert!(super::changes_settings(&click));
|
||||
assert!(super::changes_settings(&egui::Event::Text("5".into())));
|
||||
assert!(!super::changes_settings(&egui::Event::PointerMoved(egui::Pos2::ZERO)));
|
||||
assert!(!super::changes_settings(&egui::Event::MouseMoved(egui::Vec2::X)));
|
||||
}
|
||||
|
||||
/// A setting that changes in every frame (a panel's width while its edge is dragged) doesn't
|
||||
/// write the file in every frame: at most once a second, and the last change is on disk at
|
||||
/// most a second after it was made, with a frame asked for then so an idle app writes it.
|
||||
#[test]
|
||||
fn a_continuous_change_is_written_once_a_second_and_its_end_soon_after() {
|
||||
let mut app = new_app();
|
||||
let mut disk = Disk::default();
|
||||
let mut writer = PrefsWriter::read(app.prefs());
|
||||
let start = Instant::now();
|
||||
let frame = Duration::from_millis(16);
|
||||
let mut asked = None;
|
||||
// 1.5 s of dragging at 60 frames a second, with input in every frame.
|
||||
for n in 0..94u32 {
|
||||
let now = start + frame * n;
|
||||
app.preferences.browser_width = 200.0 + n as f32;
|
||||
assert!(writer.due(true, now));
|
||||
asked = writer.store(&mut disk, app.prefs(), now);
|
||||
}
|
||||
assert_eq!(disk.flushes, 2, "the first change at once, then one a second later");
|
||||
let wait = asked.expect("the last width waits, and a frame is asked for when it can be written");
|
||||
assert!(wait <= PrefsWriter::INTERVAL);
|
||||
|
||||
// The drag ends: no more input. Frames before the wait is over don't even look.
|
||||
let end = start + frame * 93;
|
||||
assert!(writer.due(false, end + frame), "the frame right after input");
|
||||
assert!(!writer.due(false, end + frame * 2), "an idle frame before the wait is over");
|
||||
// The frame asked for writes the last width.
|
||||
let then = end + wait;
|
||||
assert!(writer.due(false, then));
|
||||
assert_eq!(writer.store(&mut disk, app.prefs(), then), None);
|
||||
assert_eq!(disk.flushes, 3);
|
||||
let mut next = new_app();
|
||||
let stored = solidcraft_ui_egui::prefs::stored(|k| disk.flushed.get(k).cloned()).expect("settings on disk");
|
||||
next.load_prefs(&stored);
|
||||
assert_eq!(next.preferences.browser_width, 293.0, "the width the drag ended at");
|
||||
assert!(!writer.due(false, then + frame), "nothing waits any more");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -101,6 +101,7 @@ impl NativeMenu {
|
||||
])?;
|
||||
for (action, label) in [
|
||||
("docs", "Documentation"),
|
||||
("updates", app.tr("update.check_for_updates")),
|
||||
("shortcuts", "Keyboard Shortcuts"),
|
||||
("messages", "Messages\u{2026}"),
|
||||
("report", "Report an Issue\u{2026}"),
|
||||
|
||||
@@ -137,8 +137,11 @@ pub struct AdapterChoice {
|
||||
pub compatible: bool,
|
||||
}
|
||||
|
||||
/// Choose only surface-compatible adapters. Names saved in preferences are exact; the
|
||||
/// environment override follows wgpu's case-insensitive substring convention.
|
||||
/// Choose an adapter by name. The environment override follows wgpu's case-insensitive
|
||||
/// substring convention among surface-compatible adapters. A saved preference prefers an
|
||||
/// exact (then case-insensitive) name among compatible adapters, and if the named card is
|
||||
/// only listed as incompatible with the surface still picks it (#8341: otherwise the
|
||||
/// preference is kept in the dialog while wgpu silently uses another GPU).
|
||||
/// No match leaves selection to the normal wgpu request.
|
||||
pub fn choose_adapter(adapters: &[AdapterChoice], environment: Option<&str>, preference: Option<&str>) -> Option<usize> {
|
||||
// wgpu's environment helper panics on a missing name; an override must remain recoverable.
|
||||
@@ -149,12 +152,14 @@ pub fn choose_adapter(adapters: &[AdapterChoice], environment: Option<&str>, pre
|
||||
return Some(index);
|
||||
}
|
||||
}
|
||||
if let Some(name) = preference.filter(|s| !s.is_empty())
|
||||
&& let Some((index, _)) = compatible().find(|(_, a)| a.name == name)
|
||||
{
|
||||
return Some(index);
|
||||
}
|
||||
None
|
||||
let name = preference.filter(|s| !s.is_empty())?;
|
||||
let find = |pred: &dyn Fn(&AdapterChoice) -> bool, only_compatible: bool| {
|
||||
adapters.iter().enumerate().find(|(_, a)| (!only_compatible || a.compatible) && pred(a)).map(|(i, _)| i)
|
||||
};
|
||||
find(&|a| a.name == name, true)
|
||||
.or_else(|| find(&|a| a.name.eq_ignore_ascii_case(name), true))
|
||||
.or_else(|| find(&|a| a.name == name, false))
|
||||
.or_else(|| find(&|a| a.name.eq_ignore_ascii_case(name), false))
|
||||
}
|
||||
|
||||
/// Leave Automatic on wgpu's normal request path; named choices may defer to it too.
|
||||
@@ -292,6 +297,71 @@ pub fn window_instance_flags(flags: eframe::wgpu::InstanceFlags, intel_mac: bool
|
||||
if intel_mac && env.map(str::trim).is_none_or(str::is_empty) { flags - eframe::wgpu::InstanceFlags::VALIDATION_INDIRECT_CALL } else { flags }
|
||||
}
|
||||
|
||||
/// The environment variable that makes the macOS compatibility shim report an older OS
|
||||
/// version to wgpu's Metal backend. On OCLP-patched machines the Metal compiler accepts
|
||||
/// only up to the MSL standard of the original GPU, not the one the patched OS reports,
|
||||
/// so wgpu picks a standard that the compiler refuses (`invalid value 'metal3.2'`).
|
||||
/// Setting this variable before the process starts causes the OS to report the older
|
||||
/// version and wgpu selects a supported MSL standard (#3080, #4605).
|
||||
#[cfg(target_os = "macos")]
|
||||
pub const SYSTEM_VERSION_COMPAT_ENV: &str = "SYSTEM_VERSION_COMPAT";
|
||||
|
||||
/// The NVRAM variable that OpenCore Legacy Patcher writes on every OCLP-booted system.
|
||||
/// Its presence is the primary signal that `SYSTEM_VERSION_COMPAT=1` is needed.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub const OCLP_NVRAM_KEY: &str = "4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:OCLP-Version";
|
||||
|
||||
/// `true` if the OCLP NVRAM key is present on this system.
|
||||
///
|
||||
/// Runs `nvram <key>` and treats exit 0 as present. Any error (missing binary,
|
||||
/// permission denied, key absent) returns `false` — this is a best-effort probe.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn oclp_nvram_present() -> bool {
|
||||
std::process::Command::new("nvram").arg(OCLP_NVRAM_KEY).output().map(|o| o.status.success()).unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Whether to re-launch with `SYSTEM_VERSION_COMPAT=1`: it is not set yet and OCLP shows through
|
||||
/// the NVRAM key. The probe runs only when it is needed, so a re-launched process (variable
|
||||
/// set) never starts `nvram`.
|
||||
#[cfg(target_os = "macos")]
|
||||
fn compat_wanted(compat_set: bool, nvram: impl FnOnce() -> bool) -> bool {
|
||||
!compat_set && nvram()
|
||||
}
|
||||
|
||||
/// If this process is running under OCLP and `SYSTEM_VERSION_COMPAT` has not been set,
|
||||
/// re-launch the current binary with `SYSTEM_VERSION_COMPAT=1` added to the environment,
|
||||
/// then exit with the child's status code.
|
||||
///
|
||||
/// `SYSTEM_VERSION_COMPAT=1` must be present **before** the process starts: setting it
|
||||
/// with `std::env::set_var` inside `main` is too late because the macOS frameworks have
|
||||
/// already queried the OS version by then. Re-launching is the only safe approach that
|
||||
/// works without `unsafe` (a true `execve` replacement would require it).
|
||||
///
|
||||
/// Returns `Ok(false)` immediately when:
|
||||
/// - `SYSTEM_VERSION_COMPAT` is already set (re-launched process, no loop), or
|
||||
/// - the OCLP NVRAM key is absent.
|
||||
///
|
||||
/// Returns `Err` only when `std::env::current_exe()` fails or the child process cannot
|
||||
/// be spawned; the caller should log the error and continue normally.
|
||||
///
|
||||
/// Never returns `Ok(true)`: a successful re-launch exits the current process.
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn relaunch_with_version_compat() -> Result<bool, String> {
|
||||
// A set variable means this is the re-launched process: no loop.
|
||||
if !compat_wanted(std::env::var_os(SYSTEM_VERSION_COMPAT_ENV).is_some(), oclp_nvram_present) {
|
||||
return Ok(false);
|
||||
}
|
||||
log::info!("startup: OCLP detected; re-launching with {}=1", SYSTEM_VERSION_COMPAT_ENV);
|
||||
eprintln!("SolidCraft: OCLP detected; re-launching with {}=1", SYSTEM_VERSION_COMPAT_ENV);
|
||||
let exe = std::env::current_exe().map_err(|e| format!("could not find own executable: {e}"))?;
|
||||
let status = std::process::Command::new(&exe)
|
||||
.args(std::env::args_os().skip(1))
|
||||
.env(SYSTEM_VERSION_COMPAT_ENV, "1")
|
||||
.status()
|
||||
.map_err(|e| format!("could not re-launch with {}: {e}", SYSTEM_VERSION_COMPAT_ENV))?;
|
||||
std::process::exit(status.code().unwrap_or(1));
|
||||
}
|
||||
|
||||
/// Windows with OpenGL: the window keeps the system title bar (#2063). The window without OS
|
||||
/// decorations keeps its caption style while having no frame, and some OpenGL drivers (older
|
||||
/// Intel HD/UHD) then show the picture a caption's height lower than the window, so it no longer
|
||||
@@ -351,7 +421,8 @@ mod tests {
|
||||
assert_eq!(choose_adapter(&cards, None, Some("removed")), None);
|
||||
assert_eq!(choose_adapter(&cards, Some("missing"), Some("Discrete small")), Some(1));
|
||||
assert_eq!(choose_adapter(&cards, Some(""), Some("Discrete small")), Some(1));
|
||||
assert_eq!(choose_adapter(&cards, None, Some("Discrete")), None, "saved names are exact");
|
||||
assert_eq!(choose_adapter(&cards, None, Some("discrete small")), Some(1), "preference matches without regard to case");
|
||||
assert_eq!(choose_adapter(&cards, None, Some("Discrete")), None, "a preference is the full name, not a substring");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -360,11 +431,20 @@ mod tests {
|
||||
assert_eq!(choose_adapter(&cards, None, None), None);
|
||||
assert_eq!(choose_adapter(&cards, Some(""), Some("")), None);
|
||||
cards[2].compatible = false;
|
||||
assert_eq!(choose_adapter(&cards, Some("large"), Some("Discrete large")), None);
|
||||
// Environment still needs a compatible adapter; a preference keeps the named card (#8341).
|
||||
assert_eq!(choose_adapter(&cards, Some("large"), Some("Discrete large")), Some(2));
|
||||
assert_eq!(choose_adapter(&cards, Some("small"), None), Some(1));
|
||||
assert_eq!(choose_adapter(&[], None, None), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preference_keeps_a_named_card_even_when_surface_says_incompatible() {
|
||||
let mut cards = cards();
|
||||
cards[1].compatible = false;
|
||||
assert_eq!(choose_adapter(&cards, None, Some("Discrete small")), Some(1));
|
||||
assert_eq!(choose_adapter(&cards, None, Some("discrete SMALL")), Some(1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn automatic_adapter_preserves_the_previous_request_configuration() {
|
||||
use eframe::egui_wgpu::WgpuSetupCreateNew;
|
||||
@@ -414,6 +494,27 @@ mod tests {
|
||||
assert_eq!(window_instance_flags(on, false, None), on);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[test]
|
||||
fn oclp_relaunch_needs_the_signal_and_no_compat_variable() {
|
||||
use super::compat_wanted;
|
||||
let probed = std::cell::Cell::new(false);
|
||||
let probe = |found: bool| {
|
||||
let probed = &probed;
|
||||
move || {
|
||||
probed.set(true);
|
||||
found
|
||||
}
|
||||
};
|
||||
// The re-launched process has the variable: no probe, no second re-launch.
|
||||
assert!(!compat_wanted(true, probe(true)));
|
||||
assert!(!probed.get());
|
||||
// The OCLP NVRAM key is the signal.
|
||||
assert!(compat_wanted(false, probe(true)));
|
||||
// No signal: an ordinary Mac starts as it is.
|
||||
assert!(!compat_wanted(false, probe(false)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn switches_read_from_the_environment() {
|
||||
assert!(env_on(Some("1")) && env_on(Some("yes")) && !env_on(Some("0")) && !env_on(Some(" ")) && !env_on(None) && !env_on(Some("false")));
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'.
|
||||
Copyright 2014-2021 Google Inc. with Reserved Font Name 'Noto'.
|
||||
Subset for SolidCraft web UI (glyphs used by the zh locale); renamed Craft UI SC (no Reserved Font Name).
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License,
|
||||
Version 1.1.
|
||||
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font
|
||||
creation efforts of academic and linguistic communities, and to
|
||||
provide a free and open framework in which fonts may be shared and
|
||||
improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply to
|
||||
any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software
|
||||
components as distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to,
|
||||
deleting, or substituting -- in part or in whole -- any of the
|
||||
components of the Original Version, by changing formats or by porting
|
||||
the Font Software to a new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed,
|
||||
modify, redistribute, and sell modified and unmodified copies of the
|
||||
Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in
|
||||
Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the
|
||||
corresponding Copyright Holder. This restriction only applies to the
|
||||
primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created using
|
||||
the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,96 @@
|
||||
Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'.
|
||||
Copyright 2014-2021 Google Inc. with Reserved Font Name 'Noto'.
|
||||
Subset for SolidCraft web UI (glyphs used by the zh-TW locale); renamed Craft UI TC (no Reserved Font Name).
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License,
|
||||
Version 1.1.
|
||||
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font
|
||||
creation efforts of academic and linguistic communities, and to
|
||||
provide a free and open framework in which fonts may be shared and
|
||||
improved in partnership with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply to
|
||||
any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software
|
||||
components as distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to,
|
||||
deleting, or substituting -- in part or in whole -- any of the
|
||||
components of the Original Version, by changing formats or by porting
|
||||
the Font Software to a new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed,
|
||||
modify, redistribute, and sell modified and unmodified copies of the
|
||||
Font Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components, in
|
||||
Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the
|
||||
corresponding Copyright Holder. This restriction only applies to the
|
||||
primary font name as presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created using
|
||||
the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -204,7 +204,10 @@ constraint = [
|
||||
"c_polygon", "c_smooth", "c_symmetry", "c_tangent",
|
||||
]
|
||||
construction = [
|
||||
"centerline", "construction", "infinite",
|
||||
"centerline", "construction", "construction_line", "construction_line_angle",
|
||||
"construction_line_bisector", "construction_line_horizontal", "construction_line_parallel",
|
||||
"construction_line_perpendicular", "construction_line_tangent_at", "construction_line_tangent_external",
|
||||
"construction_line_tangent_two", "construction_line_vertical", "infinite",
|
||||
]
|
||||
mesh = [
|
||||
"mesh_body",
|
||||
|
||||
@@ -70,6 +70,16 @@ configuration_table false
|
||||
conic false
|
||||
constrainer false
|
||||
construction false
|
||||
construction_line false
|
||||
construction_line_angle false
|
||||
construction_line_bisector false
|
||||
construction_line_horizontal false
|
||||
construction_line_parallel false
|
||||
construction_line_perpendicular false
|
||||
construction_line_tangent_at false
|
||||
construction_line_tangent_external false
|
||||
construction_line_tangent_two false
|
||||
construction_line_vertical false
|
||||
contact_all false
|
||||
contact_new false
|
||||
contact_off false
|
||||
@@ -191,6 +201,7 @@ polygon false
|
||||
polygon_circumscribed false
|
||||
polygon_edge false
|
||||
presspull false
|
||||
print_face false
|
||||
project false
|
||||
project_surface false
|
||||
rack_pinion false
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Construction line through two points</title>
|
||||
<path d="M8 52L56 12" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="10 5"/>
|
||||
<circle cx="20" cy="42" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="20" cy="42" r="3.4" fill="#236ead"/>
|
||||
<circle cx="44" cy="22" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="44" cy="22" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 472 B |
@@ -0,0 +1,8 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Construction line at an angle</title>
|
||||
<path d="M10.26 48.66L58.26 48.66" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M28.65 33.23A24 24 0 0 1 34.26 48.66" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M10.26 48.66L54.26 11.66" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<circle cx="10.26" cy="48.66" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="10.26" cy="48.66" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 646 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Angle bisector</title>
|
||||
<path d="M13.92 12.18L9.92 52.17L54.92 44.17" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M12.11 30.29A22 22 0 0 1 31.58 48.33" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M9.92 52.17L47.3 11.83" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 526 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Horizontal construction line</title>
|
||||
<path d="M8 32L56 32" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="10 5"/>
|
||||
<circle cx="32" cy="32" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="32" cy="32" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 362 B |
@@ -0,0 +1,5 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Parallel construction line</title>
|
||||
<path d="M9 37L41 9" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M23 55L55 27" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="10 5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 380 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Perpendicular construction line</title>
|
||||
<path d="M8 44L56 44" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M32 8L32 56" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M32 34L42 34L42 44" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 490 B |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Tangent at a curve point</title>
|
||||
<circle cx="32" cy="34.26" r="17" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M8 17.26L56 17.26" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<circle cx="32" cy="17.26" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="32" cy="17.26" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 480 B |
@@ -0,0 +1,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Tangent through an external point</title>
|
||||
<circle cx="21.74" cy="38.77" r="14" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M53.6 8.23L28.55 55.9" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<circle cx="51.74" cy="11.77" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="51.74" cy="11.77" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 502 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Common tangent to two curves</title>
|
||||
<circle cx="20" cy="33.59" r="12" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<circle cx="46" cy="33.59" r="8" fill="none" stroke="#6f879c" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M6 19.27L58 27.36" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 509 B |
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Vertical construction line</title>
|
||||
<path d="M32 8L32 56" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round" stroke-dasharray="10 5"/>
|
||||
<circle cx="32" cy="32" r="5.8" fill="#ffffff"/>
|
||||
<circle cx="32" cy="32" r="3.4" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 360 B |
@@ -0,0 +1,19 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<title>Print Face</title>
|
||||
<path d="M9.72 26.17L4.5 20.95L4.5 40.85L9.72 46.07Z" fill="#b8c3cf"/>
|
||||
<path d="M9.72 26.17L4.5 20.95L4.5 40.85L9.72 46.07Z" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M18.77 23.15L9.72 26.17L9.72 46.07L18.77 43.05Z" fill="#328bd3"/>
|
||||
<path d="M18.77 23.15L9.72 26.17L9.72 46.07L18.77 43.05Z" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M13.55 17.93L18.77 23.15L9.72 26.17L4.5 20.95Z" fill="#e2e8ef"/>
|
||||
<path d="M13.55 17.93L18.77 23.15L9.72 26.17L4.5 20.95Z" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M50.45 37.54L38.27 25.35L38.27 33.88L50.45 46.07Z" fill="#b8c3cf"/>
|
||||
<path d="M50.45 37.54L38.27 25.35L38.27 33.88L50.45 46.07Z" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M59.5 34.53L50.45 37.54L50.45 46.07L59.5 43.05Z" fill="#8e9faf"/>
|
||||
<path d="M59.5 34.53L50.45 37.54L50.45 46.07L59.5 43.05Z" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M47.31 22.34L59.5 34.53L50.45 37.54L38.27 25.35Z" fill="#e2e8ef"/>
|
||||
<path d="M47.31 22.34L59.5 34.53L50.45 37.54L38.27 25.35Z" fill="none" stroke="#34465b" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M50.45 46.07L38.27 33.88" fill="none" stroke="#236ead" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M59.5 43.05L50.45 46.07" fill="none" stroke="#236ead" stroke-width="2.55" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M24.17 34.2L28.31 34.2" fill="none" stroke="#236ead" stroke-width="4.25" stroke-linejoin="round" stroke-linecap="round"/>
|
||||
<path d="M35.31 34.2L27.31 38.7L27.31 29.7Z" fill="#236ead"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -60,6 +60,7 @@
|
||||
"BLEND SURFACE": "سطح مزج",
|
||||
"BOUNDARY SURFACE": "سطح حدودي",
|
||||
"BROWSER": "المستعرض",
|
||||
"Back to the original order": "العودة إلى الترتيب الأصلي",
|
||||
"Ball": "كروي",
|
||||
"Bar": "قضيب",
|
||||
"Base Center": "مركز القاعدة",
|
||||
@@ -595,6 +596,8 @@
|
||||
"Snap to face and edge centres": "الالتقاط إلى مراكز الأوجه والحواف",
|
||||
"SolidCraft cannot submit reports directly. Submit on GitHub; no token is needed in the app.": "لا يستطيع SolidCraft إرسال التقارير مباشرةً. أرسلها على GitHub؛ لا حاجة إلى رمز وصول في التطبيق.",
|
||||
"SolidCraft closed before these designs were saved. Their last autosave can be opened.": "أُغلق SolidCraft قبل حفظ هذه التصاميم. يمكن فتح آخر حفظ تلقائي لها.",
|
||||
"Sort A to Z": "فرز تصاعدي",
|
||||
"Sort Z to A": "فرز تنازلي",
|
||||
"Spacing 2 must be a non-zero number": "يجب أن يكون التباعد 2 عددًا غير صفري",
|
||||
"Spacing must be a non-zero number": "يجب أن يكون التباعد عددًا غير صفري",
|
||||
"Specialise": "تخصيص",
|
||||
@@ -775,6 +778,8 @@
|
||||
"at the face": "عند الوجه",
|
||||
"bom.group_children": "الأجزاء الفرعية في صف الجزء الأصلي",
|
||||
"browser.body_name": "جسم {number}",
|
||||
"browser.calibrate_click_a": "انقر على الصورة لتحديد النقطة A، أو اكتب إحداثياتها.",
|
||||
"browser.calibrate_click_b": "انقر على الصورة لتحديد النقطة B، أو اكتب إحداثياتها.",
|
||||
"browser.calibrate_title": "معايرة: {name}",
|
||||
"browser.capture_many": "تم تحريك {count} مكوّنات دون تثبيت مواضعها.",
|
||||
"browser.capture_note": "التثبيت يحتفظ بالموضع الجديد، والإرجاع يعيده كما كان.",
|
||||
@@ -817,6 +822,8 @@
|
||||
"cmd.appearance_pick_up": "التقاط المظهر",
|
||||
"cmd.appearance_replace": "استبدال المظهر",
|
||||
"cmd.assembly_bom": "قائمة المواد",
|
||||
"cmd.assembly_mass_properties": "خصائص الكتلة",
|
||||
"cmd.body.print_face": "وجه الطباعة",
|
||||
"cmd.body_rename": "إعادة تسمية الجسم",
|
||||
"cmd.browser_collapse_all": "طي الكل",
|
||||
"cmd.browser_expand_all": "توسيع الكل",
|
||||
@@ -1101,6 +1108,16 @@
|
||||
"cmd.sheet_refold": "إعادة الطي",
|
||||
"cmd.sheet_rules": "قائمة قواعد الصفائح المعدنية",
|
||||
"cmd.sheet_unfold": "فرد",
|
||||
"cmd.sketch.construction_line": "خط إنشائي",
|
||||
"cmd.sketch.construction_line.angle": "خط إنشائي بزاوية",
|
||||
"cmd.sketch.construction_line.bisector": "منصف الزاوية",
|
||||
"cmd.sketch.construction_line.horizontal": "خط إنشائي أفقي",
|
||||
"cmd.sketch.construction_line.parallel": "خط إنشائي موازٍ",
|
||||
"cmd.sketch.construction_line.perpendicular": "خط إنشائي عمودي",
|
||||
"cmd.sketch.construction_line.tangent_at": "مماس عند نقطة على المنحنى",
|
||||
"cmd.sketch.construction_line.tangent_external": "مماس يمر بنقطة خارجية",
|
||||
"cmd.sketch.construction_line.tangent_two": "مماس مشترك",
|
||||
"cmd.sketch.construction_line.vertical": "خط إنشائي رأسي",
|
||||
"cmd.sketch_arc3d": "قوس ثلاثي الأبعاد",
|
||||
"cmd.sketch_arc_center_point": "قوس بنقطة مركز",
|
||||
"cmd.sketch_arc_tangent": "قوس مماسي",
|
||||
@@ -1231,6 +1248,7 @@
|
||||
"cmd.view.render_browser": "متصفح التصيير",
|
||||
"cmd.view.render_dock": "نقل لوحة التصيير",
|
||||
"cmd.view.render_focus": "عرض تركيز التصيير",
|
||||
"cmd.view.status_details": "تفاصيل حالة منطقة العرض",
|
||||
"cmd.view.status_items": "عناصر حالة منطقة العرض",
|
||||
"cmd.view_ambient_occlusion": "الإظلال المحيطي",
|
||||
"cmd.view_angle_readout": "زوايا العرض",
|
||||
@@ -1269,8 +1287,14 @@
|
||||
"color.hex_hint": "#rrggbb",
|
||||
"color.hue": "درجة اللون",
|
||||
"color.linear": "عرض قيم اللون في النطاق الخطي 0-1",
|
||||
"color.recent": "الألوان الأخيرة",
|
||||
"color.recent_help": "تظهر هنا الألوان التي تختارها في أي حقل لون",
|
||||
"color.saturation": "التشبع (بالمئة)",
|
||||
"color.saturation_value": "التشبع والقيمة",
|
||||
"color.selected": "اللون المحدد",
|
||||
"color.step_down": "إنقاص خطوة",
|
||||
"color.step_up": "زيادة خطوة",
|
||||
"color.value": "القيمة، أي السطوع (بالمئة)",
|
||||
"config.column_filter_empty": "لا توجد أعمدة مطابقة",
|
||||
"contact.components_count": "{count} مكوّنات",
|
||||
"contact.enabled_label": "مفعّل",
|
||||
@@ -1317,6 +1341,7 @@
|
||||
"dialog.dimension_name": "البُعد: {name}",
|
||||
"dialog.edit_title": "تعديل {title}",
|
||||
"dialog.no_shown_body": "لا يوجد جسم ظاهر لتغييره: أظهر جسمًا، أو اختر «جسم جديد»",
|
||||
"dialog.pattern_sketch_not_object": "اختر أجسامًا أو ميزات: الرسم ليس أيًّا منهما. كرّر منحنياته بأداة النمط أو المرآة داخل الرسم، أو ابثقه أولًا.",
|
||||
"dialog.select": "↖ تحديد",
|
||||
"dialog.selected_count": "↖ {count} محدد",
|
||||
"dialog.selection_guidance": "حدد مُدخلًا لتغييره. انقر على العناصر المحددة لإزالتها؛ Ctrl/Cmd مع النقر يبدّل تحديدها أيضًا. راجع المعاينة ثم اضغط موافق.",
|
||||
@@ -1374,26 +1399,243 @@
|
||||
"from the rule": "من القاعدة",
|
||||
"help.apache": "رخصة Apache 2.0",
|
||||
"help.appearance.assign": "يمنح الأجسام أو الأوجه أو المكونات المحددة لونًا أو مظهر مادة، من دون تغيير وزنها. استخدمه للتمييز بين القطع أو لمعاينة التشطيب.",
|
||||
"help.assembly.bom": "يسرد قطع التصميم أو المكوّن مع أعدادها حسب رقم القطعة، ويمكنه حفظ القائمة بصيغة CSV أو JSON. استخدمه كقائمة قطع للطلب والتجميع.",
|
||||
"help.attributions": "الإسنادات (ATTRIBUTION.md)",
|
||||
"help.build": "الإصدار {version} · الإيداع {commit} · بُني في {date}",
|
||||
"help.canvas.decal": "يضع صورة على وجه مستوٍ من النموذج مثل ملصق. استخدمه لإظهار تسمية أو شعار أو نمط مطبوع على قطعة.",
|
||||
"help.canvas.edit": "يغيّر اللوحة المرجعية: موضعها أو حجمها أو زاويتها أو عتامتها أو انعكاسها أو ظهورها أو اسمها. استخدمه لمحاذاة صورة مرجعية مع الرسم الذي تتتبعه فوقها.",
|
||||
"help.canvas.insert": "يضع صورة PNG أو JPEG على مستوى أو وجه كمرجع شبه شفاف. استخدمه لتتبع صورة أو مخطط في رسم، مع ضبط الصورة على مقاس معلوم.",
|
||||
"help.component.break_link": "يفصل مكوّنًا مرتبطًا عن ملف تصميمه مع إبقاء أجسامه كما هي. استخدمه عندما ينبغي ألا تتبع القطعة تغييرات الملف الأصلي بعد الآن.",
|
||||
"help.component.capture_position": "يحفظ مواضع القطع التي حركتها يدويًا لتصبح مواضعها المعتمدة. استخدمه بعد سحب قطع إلى أماكنها دون أن يمسكها أي مفصل.",
|
||||
"help.component.create": "يضيف مكوّنًا جديدًا فارغًا إلى التصميم داخل المكوّن النشط، ما لم تختر مكوّنًا أبًا آخر. استخدمه لمنح قطعة جديدة في تجميع مكانًا خاصًا لأجسامها ورسومها.",
|
||||
"help.component.finish_edit": "يحفظ الجزء الذي تحرّره في مكانه، ويعود إلى تجميعه ويحدّث التجميع منه. استخدمه عند الانتهاء من تغييراتك على الجزء المرتبط.",
|
||||
"help.component.from_bodies": "يحوّل كل جسم محدد إلى مكوّن مستقل يحمل اسم الجسم. استخدمه لتحويل تصميم من أجسام منفصلة إلى تجميع يمكن ربط قطعه وتحريكها.",
|
||||
"help.component.insert_design": "يدرج تصميمًا محفوظًا آخر كمكوّن مرتبط بملفه، مع وضع أجسامه الصلبة كما هي فيه. استخدمه لإعادة استخدام قطعة في تجميع واستيراد تغييراتها اللاحقة عبر تحديث الروابط.",
|
||||
"help.component.properties": "يعرض الحجم والكتلة ومركز الكتلة وعزوم القصور الذاتي لمكوّن، اعتمادًا على مواد أجسامه. استخدمه للتحقق من وزن التجميع وتوازنه.",
|
||||
"help.component.revert_position": "يعيد القطع التي حركتها يدويًا إلى مواضعها السابقة، ويتجاهل التحركات التي لم تُثبّت مواضعها. استخدمه للتراجع عن التحركات التجريبية في تجميع.",
|
||||
"help.component.update_links": "يعيد قراءة ملفات التصميم المرتبطة ويستبدل الأجسام التي تغيّرت. استخدمه بعد تعديل قطعة يستخدمها هذا التجميع.",
|
||||
"help.config.configure": "يضيف معاملات أو ميزات أو مواد أو مظاهر كأعمدة في جدول التكوينات. استخدمه لبناء نسخ متعددة من تصميم واحد، مثل مقاسات قطعة.",
|
||||
"help.config.preview": "يتحقق من أن صفًا في جدول التكوينات يُعاد بناؤه بنجاح، دون تغيير التصميم أو سجله. استخدمه قبل التبديل إلى نسخة لست متأكدًا منها.",
|
||||
"help.config.rules": "يعرض قواعد جدول التكوينات وصفوفه والصف النشط حاليًا. استخدمه لمعرفة كيف أُعدّت نسخ التصميم.",
|
||||
"help.config.table": "يعرض جدول التكوينات: صف لكل نسخة وعمود لكل معامل أو ميزة، ويبيّن هل ما زال التصميم مطابقًا للصف النشط. استخدمه لمراجعة نسخ التصميم.",
|
||||
"help.connect_note": "أعد تشغيل كل مساعد لتحميل خادم SolidCraft. نُسخ كل ملف احتياطيًا بامتداد .bak قبل تغييره.",
|
||||
"help.connect_title": "ربط مساعدي الذكاء الاصطناعي",
|
||||
"help.construct.axis.edge": "ينشئ محورًا إنشائيًا على امتداد حافة مستقيمة أو خط رسم. استخدمه كمحور لعملية دوران أو لنمط دائري أو لمفصل.",
|
||||
"help.construct.axis.normal_to_face": "ينشئ محورًا إنشائيًا يمر بنقطة ويكون عموديًا على وجه. استخدمه كمحور يبرز مستقيمًا من السطح.",
|
||||
"help.construct.axis.through_cylinder": "ينشئ محورًا إنشائيًا عبر مركز وجه أسطوانة أو مخروط أو طارة، أو حافة دائرية. استخدمه لتدوير الميزات أو تكرارها حول قطعة مستديرة.",
|
||||
"help.construct.axis.two_planes": "ينشئ محورًا إنشائيًا عند التقاء مستويين أو وجهين مسطحين. استخدمه حين يكون المحور المطلوب هو الخط بين وجهين.",
|
||||
"help.construct.axis.two_points": "ينشئ محورًا إنشائيًا يمر بنقطتين أو رأسين أو نقطتي رسم. استخدمه لمحور يمتد بين موضعين معروفين.",
|
||||
"help.construct.plane.along_path": "ينشئ مستوى إنشائيًا عموديًا على حافة أو منحنى عند موضع على امتداده. استخدمه لرسم مقطع من أجل كنس أو لمقطع عرضي للمسار.",
|
||||
"help.construct.plane.at_angle": "ينشئ مستوى إنشائيًا مائلًا بزاوية عن مستوى أو وجه، حول محور أو حافة. استخدمه للرسوم المائلة، مثل حامل مائل.",
|
||||
"help.construct.plane.midplane": "ينشئ مستوى إنشائيًا في منتصف المسافة بين مستويين أو وجهين مسطحين، أو منصّفًا لهما حيث يلتقيان بزاوية. استخدمه كمستوى تناظر عند عمل مرآة.",
|
||||
"help.construct.plane.offset": "ينشئ مستوى إنشائيًا موازيًا لمستوى أو وجه مسطح، على مسافة محددة أو عبر نقطة. استخدمه للرسم على ارتفاع محدد فوق وجه.",
|
||||
"help.construct.plane.perpendicular": "ينشئ مستوى إنشائيًا يحوي خطًا أو حافة ويكون عموديًا على مستوى أو وجه. استخدمه للرسم بشكل رأسي على النموذج على امتداد حافة.",
|
||||
"help.construct.plane.tangent": "ينشئ مستوى إنشائيًا يمس أسطوانة أو مخروطًا أو كرة أو طارة عند نقطة. استخدمه للرسم على جانب قطعة مستديرة.",
|
||||
"help.construct.plane.three_points": "ينشئ مستوى إنشائيًا يمر بثلاث نقاط. استخدمه لمستوى تحدده مواضع على النموذج، مثل ثلاث زوايا.",
|
||||
"help.construct.plane.two_edges": "ينشئ مستوى إنشائيًا يمر بحافتين مستقيمتين أو خطين يقعان في مستوى واحد. استخدمه لمستوى يقطع القطعة، مثل مستوى يمر بحافتين متقابلتين.",
|
||||
"help.construct.point.along_path": "ينشئ نقطة إنشائية عند موضع على امتداد حافة أو منحنى. استخدمها كمرجع في موضع بين طرفي المسار.",
|
||||
"help.construct.point.center": "ينشئ نقطة إنشائية في مركز حافة دائرية أو دائرة رسم أو قوس أو كرة أو طارة. استخدمها كمرجع للثقوب والمحاور والمفاصل.",
|
||||
"help.construct.point.edge_plane": "ينشئ نقطة إنشائية حيث تخترق حافة أو خط مستوى أو وجهًا مسطحًا. استخدمها لتحديد موضع عبور المسار للمستوى.",
|
||||
"help.construct.point.three_planes": "ينشئ نقطة إنشائية حيث تلتقي ثلاثة مستويات أو أوجه مسطحة. استخدمها مرجعًا لزاوية، حتى حيث لا يوجد رأس في النموذج.",
|
||||
"help.construct.point.two_edges": "ينشئ نقطة إنشائية حيث تلتقي حافتان أو خطان، أو حيث يكونان أقرب ما يمكن. استخدمها مرجعًا عند زاوية افتراضية.",
|
||||
"help.construct.point.vertex": "ينشئ نقطة إنشائية على رأس أو نقطة رسم. استخدمها مرجعًا يبقى حتى عند إخفاء الرسم أو الجسم المحيط بها.",
|
||||
"help.contact.check": "يسرد أزواج القطع في مجموعات التلامس التي تتداخل أجسامها في مواضعها الحالية. استخدمه لاكتشاف التصادمات قبل تحريك المفاصل أو تشغيل دراسة الحركة.",
|
||||
"help.contact.create": "يجمع قطعتين أو أكثر في مجموعة تلامس تمنع أجسامها من اختراق بعضها أثناء حركة المفاصل. استخدمه للقطع التي ينبغي أن تتوقف عند التلامس، مثل ذراع يصطدم بمصدّه.",
|
||||
"help.contact.disable_all": "يعطّل التلامس، فلا تعود المفاصل المحرّكة ودراسات الحركة تتوقف عند تلامس القطع. استخدمه لتحريك القطع بحرية مجددًا أو للحفاظ على سرعة استجابة تجميع كبير.",
|
||||
"help.contact.edit": "يعدّل مجموعة تلامس: قطعها أو اسمها أو حالة تعطيلها المؤقت، ويمكنه حذف المجموعة أيضًا. استخدمه لتحديد القطع التي يُمنع تداخل أجسامها.",
|
||||
"help.contact.enable_all": "يضع كل قطع التجميع في مجموعة تلامس واحدة، فلا يمكن لأي قطعتين اختراق بعضهما أثناء حركة المفاصل. استخدمه لفحص آلية كاملة بسرعة.",
|
||||
"help.contact.enable_sets": "يفعّل التلامس لمجموعات التلامس التي عرّفتها، فتتوقف المفاصل المحرّكة ودراسات الحركة حيث كانت قطعها ستخترق بعضها. استخدمه لإعادة تفعيل مجموعاتك بعد تعطيل التلامس.",
|
||||
"help.contact.list": "يسرد مجموعات التلامس في التصميم والقطع في كل مجموعة وحالة تفعيل التلامس. استخدمه لفحص إعداد التلامس قبل تحريك التجميع.",
|
||||
"help.document.inspect": "يعرض نظرة عامة على التصميم: مكوّناته وأجسامه ورسومه وميزاته ومعاملاته. استخدمه للتعرف على تصميم لم تبنِه بنفسك.",
|
||||
"help.document.units": "يغيّر الوحدات التي تُعرض بها الأطوال في التصميم، مثل mm أو البوصة. يحتفظ الشكل الهندسي بحجمه؛ ويتغير العرض والأرقام العادية فقط.",
|
||||
"help.edit.checkpoint": "يحفظ التصميم والرسم النشط وسجل التراجع كما هي الآن. استخدمه قبل تجربة شيء محفوف بالمخاطر قد ترغب في العودة منه.",
|
||||
"help.edit.restore_checkpoint": "يعود إلى نقطة حفظ مع سجل التراجع. استخدمه لتجاهل كل ما أُجري منذ نقطة الحفظ بخطوة واحدة.",
|
||||
"help.explode.create": "ينشئ عرضًا مفككًا يباعد القطع عن مركز التجميع أو ينقلها وفق التحركات التي تحددها. استخدمه لإظهار كيفية تركيب التجميع في التعليمات أو العروض التقديمية.",
|
||||
"help.face.delete": "يحذف الأوجه المحددة ويترك الأوجه المجاورة تسد الفجوة، أو يترك الفتحة مفتوحة كسطح. استخدمه لإزالة حافة مقوّسة أو ثقب أو نتوء يعترض الطريق.",
|
||||
"help.file.insert_mesh": "يضيف ملف 3MF أو STL أو OBJ أو PLY أو glTF إلى التصميم كأجسام شبكية في مكوّن جديد. استخدمه لوضع نموذج منزّل أو ممسوح ضوئيًا بجانب تصميمك كمرجع.",
|
||||
"help.file.insert_step": "يضيف ملف STEP أو IGES أو FreeCAD أو Rhino إلى التصميم كأجسام صلبة في مكوّن جديد، وتصبح قطع التجميع مكوّنات متداخلة. استخدمه لاستيراد نماذج من المورّدين أو برامج CAD الأخرى.",
|
||||
"help.file.save_mesh": "يحفظ الأجسام كشبكة STL أو 3MF أو OBJ بدرجة نعومة الوجوه المنحنية التي تختارها. استخدمه لتجهيز القطع للطباعة ثلاثية الأبعاد أو للبرامج التي تقرأ الشبكات.",
|
||||
"help.file.send_to_slicer": "يحفظ الأجسام المحددة في ملف 3MF ويفتحه في برنامج التقطيع الذي تختاره. استخدمه للانتقال من النموذج إلى الطباعة بخطوة واحدة.",
|
||||
"help.font_details": "تستخدم الواجهة خطوط egui المدمجة (Ubuntu Light وHack، بموجب رخصة Ubuntu Font ورخصة MIT/Bitstream Vera، وNoto Emoji وخط أيقونات الرموز التعبيرية بموجب OFL وMIT). يستخدم نص الرسم خط Liberation Sans (SIL OFL 1.1). حزمة الخطوط الاختيارية craft-fonts لتطبيقات Crafting (BIZ UDPGothic وShippori Mincho وBIZ UDMincho وNoto Sans CJK SC وNoto Sans Arabic، بموجب SIL OFL 1.1) غير مضمّنة في إصدارات SolidCraft.",
|
||||
"help.fonts": "الخطوط",
|
||||
"help.frame.member": "يضع مقطعًا، مثل أنبوب أو قطاع ألومنيوم مبثوق، على امتداد خطوط رسم هيكل، بعنصر واحد لكل خط. استخدمه لبناء الهياكل والرفوف والمنشآت الملحومة.",
|
||||
"help.inspect.accessibility": "يلوّن الأوجه التي تستطيع أداة الوصول إليها من اتجاه واحد، وتلك التي لا تستطيع. استخدمه لفحص قطعة للتشغيل الآلي أو القولبة من ذلك الجانب.",
|
||||
"help.inspect.center_of_mass": "يعرض مركز كتلة الأجسام، كلٍّ على حدة ومجتمعةً، بكثافة منتظمة. استخدمه لفحص التوازن ومعرفة أين ستميل القطعة.",
|
||||
"help.inspect.colored_components": "يمنح كل مكوّن لونه المؤقت الخاص دون تغيير المظاهر. استخدمه لتمييز قطع التجميع بنظرة واحدة.",
|
||||
"help.inspect.compare": "يقارن جسمين ويبيّن المواضع التي يحتوي فيها أحدهما مادة لا يحتويها الآخر، مع الحجم والانحراف. استخدمه لمقارنة قطعة معدّلة أو مستوردة بالأصل.",
|
||||
"help.inspect.continuity": "يفحص مدى نعومة التقاء الأوجه عند حوافها: فجوات أو انكسارات أو قفزات في الانحناء، ويظلّل الدرزات. استخدمه لإيجاد المواضع التي لا تلتقي فيها الأسطح بنظافة.",
|
||||
"help.inspect.curvature_comb": "يرسم أمشاطًا على المنحنيات أو الحواف أو الأوجه تُظهر أسنانها مدى شدة انحنائها. استخدمه لكشف المواضع المسطحة والانكسارات وعدم انتظام الانحناء.",
|
||||
"help.inspect.curvature_map": "يلوّن الأوجه بحسب شدة انحنائها، بالأحمر حيث يصغر نصف القطر. استخدمه لإيجاد المواضع الضيقة وللحكم على نعومة السطح.",
|
||||
"help.inspect.draft": "يلوّن الأوجه بحسب زاوية الميل بالنسبة لاتجاه السحب، ويحدد ذات الميل غير الكافي. استخدمه لفحص القطعة قبل القولبة أو الصب.",
|
||||
"help.inspect.environment_map": "يعرض النموذج بلمسة نهائية عاكسة تشبه المرآة. استخدمه للحكم على انسياب الأسطح من طريقة مرور الانعكاسات عليها.",
|
||||
"help.inspect.interference": "يجد الأجسام المتداخلة ويعرض كل تداخل مع حجمه. استخدمه لفحص التجميع بحثًا عن قطع تتصادم.",
|
||||
"help.inspect.isocurve": "يرسم المنحنيات المتساوية المعاملات للأوجه، أي الشبكة التي بُني عليها السطح. استخدمه لمعرفة كيف ينساب السطح وأين تتجمع الخطوط.",
|
||||
"help.inspect.measure": "يقيس الأطوال والمسافات والزوايا والمساحات وأنصاف الأقطار بين ما تحدده، أو حجم الأجسام وكتلتها. استخدمه للتحقق من المقاسات والخلوصات.",
|
||||
"help.inspect.minimum_radius": "يجد أصغر نصف قطر انحناء للمنحنيات أو الحواف أو الأوجه وموضعه. استخدمه للتأكد من أن أداة أو فوهة تستطيع اتباع الشكل.",
|
||||
"help.inspect.section": "يقطع العرض على امتداد مستوى ويهشّر الأوجه المقطوعة دون تغيير النموذج. استخدمه للنظر داخل القطع والتجميعات.",
|
||||
"help.inspect.zebra": "يعرض خطوطًا سوداء وبيضاء منعكسة على أوجه النموذج. استخدمه للحكم على النعومة: الخطوط التي تنقطع أو تنكسر عند حافة تدل على انتقال ضعيف.",
|
||||
"help.joint.as_built": "يربط قطعتين في موضعيهما الحاليين دون تحريك أي منهما، ويحدد الحركة المسموحة لهما. استخدمه للقطع التي وضعتها بالفعل في مواضعها النهائية.",
|
||||
"help.joint.cam": "يربط كامة دوّارة بتابع، فينزلق التابع أو يتأرجح عندما يمر محيط الكامة تحته. استخدمه للكامات واللامركزيات وآليات تشغيل الصمامات.",
|
||||
"help.joint.create": "يربط قطعتين عند أصلي المفصل اللذين تختارهما وينقل القطعة الثانية إلى موضعها، ويحدد نوع المفصل الحركة المسموحة لهما. استخدمه لبناء تجميع تتحرك قطعه مثل الآلية الحقيقية.",
|
||||
"help.joint.drive": "يضبط زاوية المفصل أو مسافته ويحرّك القطع معه ضمن حدوده، وتتبعها المفاصل المرتبطة والحلقات المغلقة. استخدمه للتحقق من أن الآلية تتحرك كما هو مقصود.",
|
||||
"help.joint.gear": "يربط مفصلين دوّارين بنسبة تروس، بحيث يؤدي تحريك أحدهما إلى دوران الآخر. استخدمه للتروس المستقيمة والحلقية، مع تحديد النسبة من أنصاف أقطار دوائر الخطوة أو أعداد الأسنان.",
|
||||
"help.joint.limits": "يضبط الحدين الأدنى والأقصى لدوران المفصل أو انزلاقه، أو يزيل هذين الحدين. استخدمه لإبقاء مفصلة أو منزلق أو ذراع ضمن نطاق حركته الحقيقي.",
|
||||
"help.joint.motion_link": "يربط مفصلين بنسبة وإزاحة، بحيث يؤدي تحريك أحدهما إلى تحريك الآخر. استخدمه لعلاقة ثابتة بين المفاصل لا تغطيها أدوات ترس أو جريدة مسننة وترس أو لولب.",
|
||||
"help.joint.origin": "يضع أصل مفصل باسم على قطعة، عند مركز وجه أو نهاية دائرية أو منتصف حافة أو ركن أو نقطة. استخدمه لتجهيز مواضع اتصال المفاصل، فالأصل المختار على وجه يتبعه عند تغيير مقاس القطعة.",
|
||||
"help.joint.rack_pinion": "يربط ترسًا دوّارًا بجريدة مسننة منزلقة، فتتحرك الجريدة بمقدار طول قوس دائرة الخطوة الذي يدور به الترس. استخدمه لمحركات الجريدة المسننة وأنظمة التوجيه ومنصات الحركة الخطية.",
|
||||
"help.joint.reach": "يحرّك نقطة على قطعة نحو هدف بتغيير مفاصل سلسلتها ضمن حدودها. استخدمه لضبط وضعية آلية حسب الموضع المطلوب لنهايتها، مثل طرف ذراع روبوت.",
|
||||
"help.joint.rigid_group": "يثبّت القطع المحددة معًا كما هي لتتحرك كقطعة واحدة. استخدمه للقطع التي تنتمي إلى وحدة واحدة ولا تتحرك بالنسبة إلى بعضها.",
|
||||
"help.joint.screw": "يربط الدوران والانزلاق بخطوة لولبية، بحيث تتقدم القطعة بمقدار تلك المسافة في كل دورة. استخدمه للوالب القيادة والبراغي والمحاور الملولبة.",
|
||||
"help.library.apply": "يطبّق مادة أو مظهرًا من ملف مكتبة محلي على أجسام أو أوجه أو مكوّنات. استخدمه لإعادة استخدام مواد حفظتها من تصميم آخر.",
|
||||
"help.library.export": "يحفظ مواد التصميم ومظاهره في ملف مكتبة. استخدمه لمشاركتها أو إعادة استخدامها في تصميمات أخرى.",
|
||||
"help.library.inspect": "يفحص ملف مكتبة ويسرد موادّه ومظاهره دون تغيير التصميم. استخدمه لمعرفة ما تحويه المكتبة قبل تطبيقها.",
|
||||
"help.licences": "الرخص",
|
||||
"help.material.assign": "يحدد المادة التي صُنعت منها الأجسام المحددة، مثل الفولاذ أو الألومنيوم أو ABS. استخدمه لتطابق الكتلة والوزن القطعة الحقيقية.",
|
||||
"help.material.properties.validate": "يفحص بطاقة بيانات مادة بحثًا عن أرقام غير متسقة أو قيم مفقودة. استخدمه قبل الاعتماد على البيانات في حساب الكتلة أو الصلابة.",
|
||||
"help.mesh.convert": "يعيد بناء جسم شبكي، مثل ملف STL، كجسم صلب قابل للتعديل بأوجه مسطحة وأسطوانية. استخدمه لتعديل القطع الميكانيكية المستوردة كأنها جسم منمذج.",
|
||||
"help.mit": "رخصة MIT",
|
||||
"help.motion.study": "يضبط قيم المفاصل عند خطوات على خط زمني ويشغّلها كرسوم متحركة. استخدمه لمشاهدة حركة آلية عبر تسلسل وفحص الخلوص أثناء الحركة.",
|
||||
"help.motion.trace": "يتتبع مسار نقطة على قطعة أثناء تشغيل دراسة الحركة أو تحريك مفصل، ويحفظه كمنحنى رسم ثلاثي الأبعاد عند التأكيد. استخدمه لرؤية مدى وصول آلية أو لبناء أشكال اعتمادًا على مسارها.",
|
||||
"help.notice": "NOTICE",
|
||||
"help.occurrence.ground": "يثبّت قطعة في موضعها أو يحررها مجددًا، بحيث تحرّك المفاصل القطع الأخرى حولها. استخدمه للإطار أو القاعدة التي يُبنى عليها باقي التجميع.",
|
||||
"help.occurrence.move": "يحرّك جزءًا في التجميع فقط ضمن درجات الحرية التي تسمح بها مفاصله. حدد وجهًا للجزء، ثم اسحب سهمًا أو قوسًا متاحًا.",
|
||||
"help.parameters.change": "يفتح جدول القيم المسماة والتعبيرات التي تتحكم في أبعاد التصميم. استخدمه لتغيير مقاس في مكان واحد فتتبعه كل الميزات التي تستخدمه.",
|
||||
"help.parameters.export": "يحفظ معاملات التصميم بصيغة CSV أو JSON. استخدمه لتعديلها في جدول بيانات أو نقلها إلى تصميم آخر.",
|
||||
"help.parameters.graph": "يبيّن أي المعاملات والميزات تستخدم أيًّا من غيرها، وأي حلقات أو أخطاء بينها. استخدمه لمعرفة ما سيتأثر بتغيير معامل.",
|
||||
"help.parameters.import": "يقرأ المعاملات من CSV أو JSON إلى التصميم، كلها أو لا شيء منها. استخدمه لإحضار قيم من جدول بيانات أو من تصميم آخر.",
|
||||
"help.parameters.move": "ينقل معاملًا من معاملات المستخدم قبل معامل آخر أو بعده في القائمة. استخدمه لإبقاء المعاملات المترابطة معًا.",
|
||||
"help.parts.fastener": "يضيف برغيًا أو مسمار ربط أو صامولة أو وردة أو دبوسًا أو محملًا قياسيًا بالمقاس الذي تختاره. عند وضعه على ثقب يستقر فيه بمفصل، فلا تحتاج إلى نمذجة أدوات التثبيت بنفسك.",
|
||||
"help.parts.insert": "يدرج قطعة قياسية من الفئة وبالمقاس والطول الذي تختاره. عند وضعها على إطار ثقب أو جداره، تستقر على الثقب بمفصل صلب.",
|
||||
"help.parts.library": "يفتح القطع القياسية: البراغي ومسامير الربط والصواميل والوردات وبراغي التثبيت ودبابيس التمركز والمحامل بالمقاسات القياسية. استخدمه لإضافة قطعة قياسية بدلًا من نمذجتها بنفسك.",
|
||||
"help.parts.resize": "يغيّر مقاس قطعة قياسية مدرجة أو طولها ويعيد بناءها، وتبقيها مفاصلها مثبتة في مكانها. استخدمه عندما يتبين أن برغيًا أطول من اللازم أو أن ثقبًا يحتاج إلى مقاس آخر.",
|
||||
"help.plastic.assign_rule": "يعيّن قاعدة بلاستيك لأجسام، فتأخذ ميزاتها البلاستيكية ميلها وخلوصها منها كقيم افتراضية. استخدمه لإعداد قطعة مقولبة مرة واحدة لكل ميزاتها.",
|
||||
"help.plastic.boss": "يضيف نتوءًا لمسمار على وجه: عمودًا مع ثقب اختياري وميل وتقويس عند الجذر وأضلاع تقوية. استخدمه لنقاط البراغي في الهياكل المقولبة أو المطبوعة.",
|
||||
"help.plastic.lip": "يضيف شفة أو أخدودًا مطابقًا على طول حافة جسم مفرَّغ. استخدمه ليتمركز نصفا الهيكل أحدهما على الآخر ويُغلقا بإحكام.",
|
||||
"help.plastic.manage_rules": "ينشئ قواعد البلاستيك ويعدّلها: المادة وسماكة الجدار وأنصاف الأقطار والخلوص والميل. استخدمها للحفاظ على اتساق ميزات القطعة المقولبة.",
|
||||
"help.plastic.rest": "يضيف مسندًا على وجه: وسادة مستديرة أو مستطيلة، مصمتة أو مجوفة، مع ميل. استخدمه كدعامة أو مُباعِد في هيكل مقولب.",
|
||||
"help.plastic.snap_fit": "يضيف خطاف وصلة كبس على وجه، بطوله وسماكته ونتوء التثبيت. استخدمه لتثبيت القطع معًا بلا براغي.",
|
||||
"help.pointcloud.insert": "أدرج مسحًا بصيغة PLY أو XYZ أو PTS كسحابة نقاط بجانب النموذج. استخدمه كمرجع عند النمذجة انطلاقًا من بيانات القياس.",
|
||||
"help.sheet.convert": "يحوّل لوحًا أو جسمًا مفرَّغًا بسماكة منتظمة إلى جسم صفائح معدنية، مع ثنيات عند الحواف التي تحددها. استخدمه لجعل قطعة موجودة قابلة للفرد.",
|
||||
"help.sheet.export_bend_table": "يحفظ جدول الثني لجسم صفائح معدنية بصيغة CSV أو JSON: الزوايا وأنصاف الأقطار ومواضع الثني في النمط المسطح. استخدمه لماكينة الثني أو الورشة.",
|
||||
"help.sheet.export_dxf": "يحفظ النمط المسطح بصيغة DXF، مع الحدود وخطوط الثني وملاحظات الثني الاختيارية. استخدمه للقطع بالليزر أو البلازما أو نفاث الماء.",
|
||||
"help.sheet.flange": "يضيف حافة مثنية: لوحًا أساسيًا من رسم، أو جدارًا على امتداد محيط رسم مفتوح، أو جدارًا مثنيًا على حواف الصفيحة. استخدمه لبناء قطع الصفائح المعدنية.",
|
||||
"help.sheet.flat_pattern": "ينشئ النمط المسطح لجسم صفائح معدنية، مع حجمه وفتحاته وخطوط الثني. استخدمه لفحص الشريحة الخام قبل قصها.",
|
||||
"help.sheet.fold": "يثني صفيحة على امتداد خط رسم بزاوية ونصف قطر محددين. استخدمه لطي صفيحة مسطحة بعد عمل القطوع فيها.",
|
||||
"help.sheet.hem": "يطوي حافة صفيحة على نفسها. استخدمه لحواف آمنة وصلبة بلا نتوءات حادة.",
|
||||
"help.sheet.manage_rules": "ينشئ قواعد الصفائح المعدنية ويعدّلها: السماكة ونصف قطر الثني ومعامل K والتفريغات والفجوات. استخدمها لمطابقة مادة ورشتك وأدواتها.",
|
||||
"help.sheet.path_flange": "يضيف سلسلة من الحواف المثنية على امتداد حافة صفيحة، متتبعًا سلسلة مفتوحة من خطوط الرسم. استخدمها لمقاطع مثل شكل U أو Z بخطوة واحدة.",
|
||||
"help.sheet.perforate": "يضيف حقلًا من الثقوب على كامل الصفيحة المسطحة، بنمط متدرج أو مربع. استخدمه للتهوية والشبكات والألواح الأخف.",
|
||||
"help.sheet.refold": "يعيد طي جسم صفائح معدنية مفرود. استخدمه بعد إضافة ميزات إلى الصفيحة المسطحة.",
|
||||
"help.sheet.unfold": "يفرد جميع ثنيات جسم صفائح معدنية. استخدمه لإضافة ثقوب أو قطوع يجب أن تعبر ثنية، ثم استخدم إعادة الطي.",
|
||||
"help.sketch.arc.center_point": "يرسم قوسًا دائريًا حول نقطة مركز، من نقطة بداية إلى نقطة نهاية. استخدمه عندما يكون مركز القوس معروفًا، مثل نصف قطر حول ثقب أو محور.",
|
||||
"help.sketch.arc.tangent": "يرسم قوسًا يبدأ من نهاية خط أو قوس ويكمل مماسًا له. استخدمه لمتابعة السلسلة بانحناء ناعم بدل زاوية حادة.",
|
||||
"help.sketch.arc.three_point": "يرسم قوسًا من نقطة بداية إلى نقطة نهاية مارًا بنقطة ثالثة. استخدمه عندما يجب أن يمر القوس بنقاط محددة لا حول مركز معروف.",
|
||||
"help.sketch.arc3d": "يرسم قوسًا دائريًا دقيقًا في الفراغ عبر ثلاث نقاط، مع تفعيل الرسم ثلاثي الأبعاد. استخدمه لانحناءات المسارات وقضبان التوجيه الخارجة عن مستوى الرسم.",
|
||||
"help.sketch.auto_constrain": "يضيف القيود التي يكاد الرسم يحققها أصلًا، مثل الأفقي أو المتوازي أو المتطابق، ثم يضيف الأبعاد حتى يصبح محددًا بالكامل. استخدمه لتثبيت رسم تقريبي بخطوة واحدة.",
|
||||
"help.sketch.auto_constrain_from_datum": "يعمل مثل «تقييد تلقائي»، لكنه يقيس المواضع من نقطة مرجعية تختارها بدل نقطة الأصل. استخدمه عندما تُحدَّد أبعاد القطعة انطلاقًا من نقطة مرجعية واحدة، كركن أو ثقب.",
|
||||
"help.sketch.blend_curve": "يصل نهايتي منحنيين بمنحنى شريحي ناعم مماس لكليهما، أو مستمر الانحناء أيضًا إن اخترت. استخدمه لسد الفجوة بين منحنيين دون التواء.",
|
||||
"help.sketch.break": "يقسم المنحنى إلى أجزاء عند تقاطع منحنيات أخرى معه، أو عند نقاط تضعها عليه. استخدمه عندما يحتاج جزء من المنحنى إلى قيده الخاص أو إلى حذفه وحده.",
|
||||
"help.sketch.cancel": "يغادر الرسم ويتجاهل كل ما تغيّر منذ إنشائه أو فتحه للتعديل. ويمكن استعادة التغييرات بأمر «تراجع».",
|
||||
"help.sketch.centerline": "يبدّل الخطوط بين خطوط عادية وخطوط المركز، وهي محاور لا تدخل في المقاطع. استخدم خط المركز محورًا لأمر «دوران» أو «مرآة» أو لقيد التناظر.",
|
||||
"help.sketch.chamfer.distance_angle": "يشطف الزاوية بين خطين بمسافة على طول الخط الأول وبزاوية. استخدمه عندما يعطي المخطط الشطف بطول وزاوية، مثل 2 mm × 30°.",
|
||||
"help.sketch.chamfer.equal_distance": "يشطف الزاوية بين خطين بالمسافة نفسها على طول كليهما. استخدمه للشطف المعتاد بزاوية 45° على المحيط.",
|
||||
"help.sketch.chamfer.two_distance": "يشطف الزاوية بين خطين بمسافة مستقلة على كل خط. استخدمه للشطف بزاوية غير 45°، المعطى بطولين.",
|
||||
"help.sketch.circle.center": "يرسم دائرة من مركزها وقطرها. استخدمه للثقوب والنتوءات والميزات المستديرة الأخرى المعروف مركزها.",
|
||||
"help.sketch.circle.three_point": "يرسم دائرة تمر بثلاث نقاط. استخدمه عندما يجب أن تمر الدائرة بنقاط محددة، مثلًا من هندسة موجودة.",
|
||||
"help.sketch.circle.three_tangent": "يرسم دائرة تمس ثلاثة خطوط أو دوائر أو أقواس. استخدمه لإدخال دائرة في الفراغ بين ثلاثة منحنيات، مثل الدائرة المحاطة بمثلث.",
|
||||
"help.sketch.circle.two_point": "يرسم دائرة من طرفي قطرها. استخدمه عندما تكون نقطتا حافة الدائرة معروفتين لا مركزها.",
|
||||
"help.sketch.circle.two_tangent": "يرسم دائرة بحجم محدد تمس خطين أو دائرتين أو قوسين. استخدمه لتقويس ثابت نصف القطر بين منحنيين.",
|
||||
"help.sketch.conic": "يرسم منحنى مخروطيًا بين نقطتي نهاية، يتشكل بنقطة قمة وقيمة rho. استخدمه لانتقالات ناعمة تضبط امتلاءها من المسطح إلى ما يقارب زاوية حادة.",
|
||||
"help.sketch.constrainer": "يطبق القيد الذي يكاد منحنى أو منحنيان محددان يحققانه، مثل الأفقي أو التوازي أو التماس أو التساوي. استخدمه لتهذيب رسم يدوي علاقة بعد أخرى.",
|
||||
"help.sketch.constraint.coincident": "يجعل نقطة تقع على نقطة أخرى أو على منحنى أو على محور الرسم. استخدمه لسد الفجوات في المقطع أو لوضع نقطة على خط.",
|
||||
"help.sketch.constraint.collinear": "يجعل خطين يقعان على خط مستقيم واحد. استخدمه لمحاذاة الحواف المتقطعة، مثل جانبي حز.",
|
||||
"help.sketch.constraint.concentric": "يعطي دائرتين أو قوسين المركز نفسه. استخدمه للحلقات والتجاويف المتدرجة والأعمدة ذات الأكتاف.",
|
||||
"help.sketch.constraint.curvature": "يجعل منحنيين يلتقيان عند نقطة نهاية يتابعان بالانحناء نفسه (G2). استخدمه حيث لا يكفي الوصل المماسي نعومة، مثلًا على الأسطح الظاهرة.",
|
||||
"help.sketch.constraint.equal": "يجعل الخطوط بالطول نفسه، أو الدوائر والأقواس بنصف القطر نفسه. استخدمه ليتحكم بُعد واحد في عدة ميزات متماثلة.",
|
||||
"help.sketch.constraint.fix": "يثبّت النقاط أو المنحنيات في مكانها، أو يفك تثبيتها. استخدمه للهندسة التي يجب ألا تتحرك عند سحب الرسم أو حله.",
|
||||
"help.sketch.constraint.horizontal_vertical": "يجعل خطًا، أو الخط بين نقطتين، أفقيًا أو رأسيًا، أيهما أقرب. استخدمه لمحاذاة المحيط مع محاور الرسم.",
|
||||
"help.sketch.constraint.midpoint": "يضع نقطة في منتصف خط، أو يجعل منتصفي خطين يلتقيان. استخدمه لتوسيط الهندسة على حافة.",
|
||||
"help.sketch.constraint.parallel": "يجعل خطين متوازيين. استخدمه للأضلاع التي يجب أن تبقى متوازية عند تغيير الأبعاد الأخرى.",
|
||||
"help.sketch.constraint.perpendicular": "يجعل خطين يلتقيان بزاوية قائمة. استخدمه للزوايا القائمة بين خطوط ليست على محاور الرسم.",
|
||||
"help.sketch.constraint.polygon": "يجعل سلسلة مغلقة من الخطوط مضلعًا منتظمًا: أضلاع متساوية وكل زاوية على دائرة واحدة. استخدمه لجعل مضلع مرسوم يدويًا منتظمًا والحفاظ على ذلك.",
|
||||
"help.sketch.constraint.symmetry": "يجعل نقطتين أو منحنيين متناظرين حول خط أو نقطة. استخدمه للحفاظ على تناظر المقطع عند تغيير أحد جانبيه.",
|
||||
"help.sketch.constraint.tangent": "يجعل منحنيين يتماسان مماسيًا، مثل خط وقوس. استخدمه لوصلات ناعمة بلا التواء.",
|
||||
"help.sketch.construction": "يبدّل المنحنيات بين الهندسة العادية والهندسة الإنشائية التي تتجاهلها المقاطع. استخدم المنحنيات الإنشائية مساعدات للتخطيط والمراجع والأبعاد.",
|
||||
"help.sketch.construction_line": "أنشئ خطًا إنشائيًا لا نهائيًا يمر بنقطتين. استخدمه لتخطيط الرسم دون تقسيم مقاطعه.",
|
||||
"help.sketch.construction_line.angle": "أنشئ خطًا إنشائيًا لا نهائيًا بزاوية من محور X للرسم. اختر النقطة ثم اكتب الزاوية، أو اختر اتجاهه.",
|
||||
"help.sketch.construction_line.bisector": "اختر خطين مستقيمين متقاطعين في الرسم، ثم اختر أحد منصفي الزاوية. يتبع الناتج الخطين اللذين أُنشئ منهما.",
|
||||
"help.sketch.construction_line.horizontal": "أنشئ خطًا إنشائيًا أفقيًا لا نهائيًا يمر بنقطة. يحافظ القيد الأفقي على الاتجاه بعد التعديلات.",
|
||||
"help.sketch.construction_line.parallel": "اختر خطًا مستقيمًا في الرسم ثم ضع خطًا إنشائيًا لا نهائيًا موازيًا له. انقر بزر الفأرة الأيمن لتغيير المرجع.",
|
||||
"help.sketch.construction_line.perpendicular": "اختر خطًا مستقيمًا في الرسم ثم ضع خطًا إنشائيًا لا نهائيًا عموديًا عليه. انقر بزر الفأرة الأيمن لتغيير المرجع.",
|
||||
"help.sketch.construction_line.tangent_at": "أنشئ مماسًا عند نقطة على دائرة أو قوس دائري، أو عند نهاية منحنى شريحي مفتوح أو قطع مخروطي مفتوح. اختر المنحنى ثم نقطة التماس.",
|
||||
"help.sketch.construction_line.tangent_external": "اختر دائرة أو قوسًا دائريًا، ثم نقطة خارجية وحل المماس. تعرض المعاينة نقاط التماس الواقعة على القوس المرسوم فقط.",
|
||||
"help.sketch.construction_line.tangent_two": "اختر دائرتين أو قوسين دائريين ثم اختر مماسًا مشتركًا من المعاينة. يجب أن تقع نقطتا التماس على المنحنيين المرسومين.",
|
||||
"help.sketch.construction_line.vertical": "أنشئ خطًا إنشائيًا رأسيًا لا نهائيًا يمر بنقطة. يحافظ القيد الرأسي على الاتجاه بعد التعديلات.",
|
||||
"help.sketch.copy": "ينسخ منحنيات الرسم ونقاطه المحددة مع القيود والأبعاد بينها. الصقها في هذا الرسم أو في رسم آخر.",
|
||||
"help.sketch.create": "يبدأ رسمًا ثنائي الأبعاد جديدًا على مستوى أو على وجه مسطح من النموذج. يبدأ كل بثق ودوران وكنس برسم.",
|
||||
"help.sketch.cut": "ينسخ هندسة الرسم المحددة ويحذفها من الرسم بخطوة تراجع واحدة. الصقها في مكان آخر من هذا الرسم أو في رسم آخر.",
|
||||
"help.sketch.dimension": "يضيف بُعدًا حاكمًا: طولًا أو مسافة أو زاوية أو نصف قطر أو قطرًا بحسب ما تختاره. اكتب قيمة أو اسم معامل فيتبعها الرسم.",
|
||||
"help.sketch.edit": "يفتح رسمًا موجودًا للتعديل. تتحدّث الميزات المبنية عليه عند إنهاء الرسم.",
|
||||
"help.sketch.ellipse": "يرسم قطعًا ناقصًا من مركزه ونهاية محوره الأكبر ونقطة على جانبه الأصغر. استخدمه للفتحات البيضاوية والكامات وغيرها من الأشكال المستديرة المتطاولة.",
|
||||
"help.sketch.equation_curve": "يرسم منحنى من صيغ على مدى: x(t) و y(t)، أو y = f(x). يمكن أن تستخدم الصيغ المعلمات فيتبعها المنحنى: استخدمه لموجة جيبية أو لولب أو منحنى انفلات لسن ترس.",
|
||||
"help.sketch.extend": "يمدد خطًا أو قوسًا حتى أقرب منحنى في طريقه، أو ينمّي منحنيين حتى يلتقيا. استخدمه لسد الفجوات في المقطع بعد القص أو التعديل.",
|
||||
"help.sketch.fillet": "يقوّس الزاوية التي يلتقي فيها خطان أو قوسان بقوس ذي نصف قطر محدد. الزوايا المقوّسة معًا تشترك في نصف قطر واحد.",
|
||||
"help.sketch.finish": "يغادر الرسم ويعود إلى النموذج. تصبح مقاطعه المغلقة جاهزة للبثق والدوران وغيرهما من الميزات.",
|
||||
"help.sketch.finish_auto_constrain": "يشغّل «تقييد تلقائي» على الرسم ثم ينهيه. استخدمه لترك الرسم محددًا بالكامل بخطوة واحدة.",
|
||||
"help.sketch.fit_curves_to_section": "يقطع شبكة أو جسمًا صلبًا بمستوى الرسم ويلائم خطوطًا وأقواسًا مع المقطع. استخدمه لإعادة بناء قطعة ممسوحة أو مستوردة كرسم قابل للتعديل.",
|
||||
"help.sketch.include_3d": "يجلب حواف النموذج ورؤوسه ومنحنيات رسوم أخرى إلى هذا الرسم كمراجع مرتبطة، ويسطّح ما هو خارج مستواه عليه. استخدمه للبناء على هندسة لا تقع في مستوى الرسم.",
|
||||
"help.sketch.infinite": "يبدّل الخطوط بين خطوط عادية وخطوط إنشائية لا نهائية تمتد عبر العرض كله. استخدمها مراجع للتخطيط لا تقصر عن الحاجة أبدًا.",
|
||||
"help.sketch.insert_dxf": "يقرأ منحنيات مخطط DXF إلى رسم بالمقياس والدوران والموضع الذي تحدده. استخدمه للبناء على مخطط ثنائي الأبعاد من برنامج آخر، مثل محيط للقطع بالليزر.",
|
||||
"help.sketch.insert_svg": "يقرأ مسارات مخطط SVG إلى رسم بالمقياس والدوران والموضع الذي تحدده. استخدمه لتحويل شعار أو محيط متجهي إلى منحنيات يمكنك بثقها.",
|
||||
"help.sketch.inspect": "يفتح تقريرًا عن الرسم المفتوح: عدد درجات الحرية المتبقية وهل هو مقيد بالكامل. استخدمه لمعرفة ما لا يزال يتحرك قبل إنهاء الرسم.",
|
||||
"help.sketch.intersect": "يضيف المنحنيات أو النقاط التي تقطع فيها أجسام أو أوجه أو حواف أو رسوم أخرى مستوى الرسم. تبقى مرتبطة وتتبع النموذج عندما يتغير.",
|
||||
"help.sketch.intersection_curve": "ينشئ منحنيات ثلاثية الأبعاد حيث يلتقي جسمان أو وجهان، مرتبطة بهما. استخدمها مسارات أو قضبان توجيه تتبع النموذج.",
|
||||
"help.sketch.isoparametric_curve": "ينشئ منحنى ثلاثي الأبعاد على اتجاه U أو V للوجه عبر نقطة تختارها، مرتبطًا بالوجه. استخدمه مسارًا أو خط تقسيم يتبع السطح.",
|
||||
"help.sketch.line": "يرسم خطوطًا متصلة نقطة بنقطة، كسلسلة مفتوحة أو محيط مغلق. هو الأداة الأساسية لمعظم المقاطع.",
|
||||
"help.sketch.line.midpoint": "يرسم خطًا من منتصفه إلى أحد طرفيه، ويعكس الطرف الآخر. استخدمه للخطوط المتمركزة على نقطة، مثل حافة متناظرة.",
|
||||
"help.sketch.line3d": "يرسم خطوطًا مستقيمة متصلة بين نقاط في الفراغ، مع تفعيل الرسم ثلاثي الأبعاد. استخدمه للمسارات والإطارات الخارجة عن مستوى الرسم.",
|
||||
"help.sketch.mirror": "يعكس منحنيات الرسم ونقاطه حول خط أو محور ويضيف قيود تناظر. استخدمه لرسم نصف مقطع متناظر ثم إكماله.",
|
||||
"help.sketch.move": "يحرّك منحنيات الرسم ونقاطه أو يدوّرها، أو يفعل ذلك بنسخة منها. استخدمه لإعادة وضع الهندسة مع الحفاظ على شكلها وقيودها.",
|
||||
"help.sketch.offset": "ينشئ نسخة من سلسلة منحنيات على مسافة محددة، من جانب واحد أو من الجانبين. استخدمه للجدران والمحيطات والخلوصات؛ وتبقى المسافة بُعدًا قابلًا للتعديل.",
|
||||
"help.sketch.paste": "يلصق في الرسم النشط هندسة رسم نسختها أو قصصتها. ضعها عند نقطة أو أزحها بمقدار.",
|
||||
"help.sketch.pattern.circular": "ينسخ هندسة الرسم حول نقطة مركز، على دائرة كاملة أو زاوية محددة. استخدمه لدوائر البراغي والأذرع والأسنان.",
|
||||
"help.sketch.pattern.rectangular": "ينسخ هندسة الرسم في صفوف وأعمدة بمسافات محددة. استخدمه لشبكات الثقوب والشقوق وفتحات التهوية.",
|
||||
"help.sketch.point": "يضع نقطة رسم. استخدمها مرجعًا للأبعاد والقيود ومراكز الثقوب أو الميزات اللاحقة.",
|
||||
"help.sketch.point3d": "يضع نقطة في الفراغ، مع تفعيل الرسم ثلاثي الأبعاد. استخدمها مرجعًا للمنحنيات والمسارات الثلاثية الأبعاد.",
|
||||
"help.sketch.polygon.circumscribed": "يرسم مضلعًا منتظمًا حول دائرة، بحجم يُحدد من مركزها إلى منتصف ضلع. استخدمه عندما يكون العرض بين الضلعين المتقابلين معروفًا، كما في صامولة سداسية.",
|
||||
"help.sketch.polygon.edge": "يرسم مضلعًا منتظمًا من طرفي ضلع واحد. استخدمه عندما يكون طول الضلع وموضعه معروفين.",
|
||||
"help.sketch.polygon.inscribed": "يرسم مضلعًا منتظمًا داخل دائرة، بحجم يُحدد من مركزها إلى أحد رؤوسه. استخدمه عندما يكون البعد بين الرأسين المتقابلين معروفًا.",
|
||||
"help.sketch.project": "يجلب حواف النموذج وأوجهه ورؤوسه ومنحنيات رسوم أخرى إلى هذا الرسم، مسقطة على مستواه. تبقى مرتبطة وتتبع النموذج عندما يتغير.",
|
||||
"help.sketch.project_to_surface": "يسقط منحنيات رسوم أخرى على وجه في اتجاه العمودي على مستوى هذا الرسم، كمنحنيات ثلاثية الأبعاد مرتبطة. استخدمه لوضع شعار أو خط تقسيم أو مسار على سطح منحنٍ.",
|
||||
"help.sketch.rectangle.center": "يرسم مستطيلًا من مركزه وأحد أركانه. استخدمه للمحيطات المتمركزة على نقطة، مثل نقطة الأصل.",
|
||||
"help.sketch.rectangle.rounded": "يرسم مستطيلًا بأركان أربعة مدوّرة بنصف قطر واحد. استخدمه للألواح والأغطية والفتحات ذات الأركان المدوّرة.",
|
||||
"help.sketch.rectangle.three_point": "يرسم مستطيلًا من حافة واحدة ونقطة على الجانب المقابل. استخدمه للمستطيلات المائلة عن محاور الرسم.",
|
||||
"help.sketch.rectangle.two_point": "يرسم مستطيلًا من ركنين متقابلين. استخدمه لمحيطات الألواح والكتل والجيوب.",
|
||||
"help.sketch.scale": "يغيّر مقياس منحنيات الرسم ونقاطه بمعامل حول نقطة أساس. استخدمه لتغيير حجم جزء من الرسم دون إعادة رسمه.",
|
||||
"help.sketch.slot.arc_center": "يرسم شقًا منحنيًا بعرض محدد على امتداد قوس يُحدد بمركزه وبدايته ونهايته. استخدمه لشقوق الضبط حول محور.",
|
||||
"help.sketch.slot.arc_three_point": "يرسم شقًا منحنيًا بعرض محدد على امتداد قوس يمر بثلاث نقاط. استخدمه عندما يجب أن يمر مسار الشق بنقاط محددة.",
|
||||
"help.sketch.slot.center_point": "يرسم شقًا مستقيمًا بعرض محدد من مركزه إلى مركز قوس أحد طرفيه. استخدمه للشقوق المتمركزة على نقطة.",
|
||||
"help.sketch.slot.center_to_center": "يرسم شقًا مستقيمًا بعرض محدد بين مركزي قوسي طرفيه. استخدمه للشقوق المقيّسة من مركز إلى مركز، مثل شقوق ضبط البراغي.",
|
||||
"help.sketch.slot.overall": "يرسم شقًا مستقيمًا بعرض محدد من طرفه الخارجي إلى الطرف الآخر. استخدمه عندما يكون الطول الكلي للشق هو المهم.",
|
||||
"help.sketch.spline.control_point": "يرسم منحنى شريحيًا تكعيبيًا يتشكل بنقاط تحكم لا يمر بها. استخدمه للمنحنيات الناعمة المنسابة التي تشكلها بتحريك النقاط.",
|
||||
"help.sketch.spline.control_point_5": "يرسم منحنى شريحيًا من الدرجة 5 يتشكل بنقاط تحكم. استخدمه حيث يجب أن تلتقي المنحنيات بانحناء أنعم، مثلًا على الأسطح الظاهرة ذات التصميم الانسيابي.",
|
||||
"help.sketch.spline.fit_point": "يرسم منحنى شريحيًا ناعمًا يمر بكل نقطة تضعها، مفتوحًا أو مغلقًا. استخدمه لتتبع شكل عبر نقاط معروفة.",
|
||||
"help.sketch.spline3d": "يرسم منحنى ناعمًا في الفراغ عبر نقاط، مع تفعيل الرسم ثلاثي الأبعاد. استخدمه لمسارات الكنس ومسارات الكابلات الخارجة عن مستوى الرسم.",
|
||||
"help.sketch.spun_profile": "ينشئ في مستوى الرسم المحيط الذي يمسحه جسم عند دورانه حول محور. استخدمه للحصول على صورة ظلية لقطعة مشغولة بالخراطة من أجل أمر «دوران» أو مخطط.",
|
||||
"help.sketch.text": "يكتب نصًا في الرسم بخط وارتفاع وزاوية تختارها، ويمكن لكلماته أن تتبع المعلمات. ابثقه أو حوّله إلى نقش بارز للملصقات والكتابة.",
|
||||
"help.sketch.transform": "يغيّر مقياس هندسة الرسم ويدوّرها ويحرّكها حول نقطة مركز بخطوة واحدة. استخدمه لإعادة وضع تحديد وتغيير حجمه معًا.",
|
||||
"help.sketch.trim": "يزيل الجزء من المنحنى بين أقرب نقطتي تقاطع حول موضع نقرتك. استخدمه لتنظيف الخطوط المتداخلة وتحويلها إلى مقطع مغلق.",
|
||||
"help.solid.align": "يحرّك الأجسام المحددة بحيث تلتقي نقطة أو وجه أو مستوى منها بنقطة أو وجه أو مستوى في مكان آخر. استخدمه لوضع قطعة ملاصقة لأخرى دون قياس المسافة.",
|
||||
"help.solid.boundary_fill": "ينشئ أجسامًا صلبة من المناطق التي تحيط بها أجسام أدوات متداخلة، مع تعبئة المناطق التي تختارها فقط. استخدمه لبناء شكل من الحيز الذي تحدّه عدة أجسام معًا.",
|
||||
"help.solid.bounding_solid": "ينشئ صندوقًا يحيط بالأجسام المحددة، مع هامش اختياري. استخدمه لمعرفة الأبعاد الكلية لقطعة أو كخامة أولية تُشغّل منها.",
|
||||
"help.solid.box": "ينشئ صندوقًا بطول وعرض وارتفاع، انطلاقًا من نقطة ركن أو متمركزًا حول نقطة. استخدمه لإنشاء كتلة سريعة أو شكل مؤقت أو جسم تُقطع فيه ميزات.",
|
||||
"help.solid.chamfer": "يقطع الحواف المحددة بشطفة مستوية بالمسافة التي تحددها. استخدمه لكسر الحواف الحادة أو لتسهيل إدخال مسمار أو برغي.",
|
||||
"help.solid.coil": "ينشئ جسمًا حلزونيًا مثل النابض من قطر وعدد لفات وارتفاع أو خطوة، وبمقطع دائري أو مربع. استخدمه للنوابض والملفات والنتوءات الحلزونية.",
|
||||
"help.solid.combine": "يضم الأجسام، أو يقتطعها من جسم هدف، أو يُبقي الحجم المشترك بينها فقط، ويمكنه الاحتفاظ بأجسام الأداة. استخدمه لدمج القطع، أو لقطع شكل بشكل آخر، أو لمعرفة موضع تداخل جسمين.",
|
||||
"help.solid.cone": "ينشئ مخروطًا من دائرة قاعدة وارتفاع، أو مخروطًا ناقصًا عند تحديد نصف قطر للقمة أيضًا. استخدمه للأشكال المستدقة والقمع والتجاويف المخروطية والرؤوس المدببة.",
|
||||
"help.solid.cylinder": "ينشئ أسطوانة بنصف قطر أو قطر وارتفاع، قائمة عند نقطة على امتداد محور. استخدمه للأعمدة والدبابيس والنتوءات الدائرية والخامات الأسطوانية.",
|
||||
"help.solid.draft": "يميل الأوجه المحددة بالزاوية التي تحددها، مقيسةً من مستوى محايد. استخدمه في القطع المقولبة أو المصبوبة كي تخرج من القالب بسهولة.",
|
||||
"help.solid.emboss": "يبرز مقاطع رسم مثل نص أو شعار من وجه، أو يغورها فيه. استخدمه للكتابات والتسميات والعلامات على الوجوه المستوية أو المستديرة.",
|
||||
"help.solid.extrude": "يدفع مقطع رسم إلى ثلاثي الأبعاد على مسافة محددة، بإضافة مادة أو إزالتها. استخدمه لتحويل مخطط مسطح إلى كتلة أو نتوء أو تجويف.",
|
||||
"help.solid.fillet": "يقوّس الحواف المحددة بانحناء دائري ناعم بنصف القطر الذي تحدده. استخدمه لتنعيم الحواف الحادة من أجل المتانة أو الراحة أو المظهر.",
|
||||
"help.solid.hole": "يحفر ثقبًا دائريًا بالقطر الذي تحدده عند نقطة مختارة على وجه. استخدمه لفتحات البراغي والمسامير والفتحات الدائرية البسيطة الأخرى.",
|
||||
@@ -1402,20 +1644,60 @@
|
||||
"help.solid.move": "يحرّك الأجسام المحددة أو يدوّرها، أو نسخة منها، بالمسافة والزاوية اللتين تحددهما. استخدمه لتغيير موضع جسم أو لإنشاء جسم ثانٍ في مكان آخر.",
|
||||
"help.solid.offset_face": "يدفع الأوجه المحددة إلى الداخل أو الخارج بالمسافة التي تحددها، وتتبعها الأوجه المحيطة. استخدمه لزيادة سماكة جدار أو عمق جيب أو ارتفاع نتوء دون تعديل الرسم.",
|
||||
"help.solid.pattern.circular": "يكرر العناصر المحددة حول محور، بالعدد والزاوية الكلية اللذين تحددهما. استخدمه لدوائر البراغي والأذرع والزعانف والأسنان.",
|
||||
"help.solid.pattern.path": "ينسخ ميزات أو أجسامًا على امتداد مسار رسم، بالعدد والتباعد. استخدمه لثقوب على حافة منحنية أو قطع على سكة.",
|
||||
"help.solid.pattern.rectangular": "يكرر العناصر المحددة في اتجاه واحد أو اتجاهين بالعدد والتباعد اللذين تحددهما. استخدمه لصفوف الثقوب والأضلاع والمسامير والأرجل وشبكاتها.",
|
||||
"help.solid.pipe": "ينشئ أنبوبًا دائريًا على مسار من منحنيات الرسم، مصمتًا أو مجوفًا بسماكة جدار محددة. استخدمه للأنابيب والأسلاك والكابلات والقضبان.",
|
||||
"help.solid.press_pull": "يضيف المادة أو يزيلها حين تسحب وجهًا، أو يقوّس الحواف حين تسحبها. استخدمه لإجراء تعديلات سريعة على النموذج مباشرة.",
|
||||
"help.solid.remove": "يُخرج الأجسام المحددة من التصميم بدءًا من هذه النقطة في السجل، وتحتفظ بها الخطوات السابقة. استخدمه للتخلص من جسم مساعد، مثل أداة قطع لم تعد تحتاجها.",
|
||||
"help.solid.replace_face": "ينقل الأوجه المستوية المحددة إلى مستوى أو إلى وجه موازٍ، فيطول الجسم أو يقصر ليبلغه. استخدمه لجعل وجه مستويًا مع قطعة أخرى أو مع مستوى إنشائي.",
|
||||
"help.solid.revolve": "يدير مقطع رسم حول محور لصنع جسم دائري. استخدمه للأعمدة والمقابض والأوعية وأي قطعة دائرية حول خط مركزي.",
|
||||
"help.solid.rib": "يضيف ضلع تقوية رقيقًا على امتداد منحنى رسم مفتوح، ممتدًا حتى الوجوه التالية للجسم. استخدمه لتقوية الجدران والزوايا، مثلًا في القطع المقولبة أو المطبوعة.",
|
||||
"help.solid.scale": "يكبّر الأجسام المحددة أو يصغّرها بمعامل، متساوٍ في كل الاتجاهات أو مختلف لكل محور. استخدمه لتغيير حجم شكل مستورد أو لحساب الانكماش.",
|
||||
"help.solid.shell": "يفرّغ الجسم الصلب تاركًا جدرانًا بالسماكة التي تحددها، ويمكنه فتح الأوجه التي تختارها. استخدمه للصناديق والأغطية والقطع الأخرى رقيقة الجدران.",
|
||||
"help.solid.sphere": "ينشئ كرة بنصف قطر أو قطر حول نقطة مركز. استخدمه للكرات والمقابض والنهايات المستديرة.",
|
||||
"help.solid.split_body": "يقسم جسمًا إلى أجسام منفصلة بمستوى أو بوجه جسم آخر أو بخط من رسم. استخدمه لصنع قطع تُطبع أو تُشغَّل أو تُلوَّن كلٌّ على حدة.",
|
||||
"help.solid.split_face": "يقسم الأوجه المحددة على طول مستوى أو وجه جسم آخر أو منحنيات رسم، دون قطع الجسم. استخدمه لإعطاء جزء من وجه ميلًا أو لونًا أو إزاحة خاصة به.",
|
||||
"help.solid.sweep": "يسحب مقطع رسم على طول مسار لصنع جسم صلب. استخدمه للأنابيب والقضبان والمقابض وأي قطعة ثابتة المقطع تتبع منحنى.",
|
||||
"help.solid.thread": "يضيف قلاوظًا متريًا بمعيار ISO إلى وجه أسطواني، إما كتمثيل شكلي أو محفورًا في الجسم. استخدمه للبراغي والثقوب الملولبة والقطع اللولبية المطبوعة.",
|
||||
"help.solid.torus": "ينشئ حلقة بنصف قطر رئيسي حول محورها ونصف قطر ثانوي لمقطعها الدائري. استخدمه لحلقات منع التسرب والمقابض والنتوءات الحلقية المستديرة.",
|
||||
"help.solid.web": "يضيف جسر تقوية رقيقًا على امتداد كل منحنى رسم مفتوح، يمتد كل منها حتى الوجوه التالية للجسم. استخدمه لإنشاء شبكة من الجدران الداعمة داخل الأغلفة والصواني.",
|
||||
"help.surface.blend": "ينشئ سطحًا يصل بين حواف جسمين، مماسًّا أو متصل الانحناء مع كليهما. استخدمه لوصل سطحين بنعومة عبر فجوة.",
|
||||
"help.surface.boundary": "ينشئ سطحًا يملأ حلقة من منحنيين إلى أربعة منحنيات رسم، أو شبكة من المنحنيات. استخدمه للوحات حرة الشكل تحددها حوافها.",
|
||||
"help.surface.extend": "يمدّد سطحًا إلى ما بعد حوافه، بمسافة أو حتى مستوى أو وجه. استخدمه لكي تتداخل الأسطح قبل القص أو الخياطة.",
|
||||
"help.surface.extrude": "يدفع منحنيات أو مقاطع رسم مسافة محددة لتكوين سطح، جدران فقط بلا أغطية. استخدمه للجدران الرقيقة وأدوات القطع أو التقسيم.",
|
||||
"help.surface.fair": "ينعّم داخل الأوجه حرة الشكل مع بقاء حوافها ثابتة. استخدمه لتسوية النتوءات والانعكاسات المتموجة في السطح.",
|
||||
"help.surface.loft": "ينشئ سطحًا يمر عبر مقطعين أو أكثر بالترتيب، بلا أغطية. استخدمه للأغلفة والانتقالات بين أشكال مختلفة.",
|
||||
"help.surface.match": "يعيد بناء حافة سطح لتلتقي بحافة جسم آخر، بمماسية أو انحناء متطابق. استخدمه لإغلاق درزة بنعومة بين سطحين.",
|
||||
"help.surface.offset": "ينشئ نسخة من الأوجه على مسافة على امتداد اتجاهاتها العمودية، كجسم سطحي جديد. استخدمه للأغلفة أو الخلوصات أو الجانب الآخر من جدار.",
|
||||
"help.surface.patch": "يملأ منطقة رسم أو حلقة مغلقة من الحواف بوجه، مسطح أو منحنٍ بنعومة. استخدمه لسدّ الثقوب في جسم سطحي.",
|
||||
"help.surface.reverse_normal": "يقلب أوجه جسم سطحي بحيث يتجه سطحها الخارجي إلى الجهة الأخرى. استخدمه قبل التثخين أو الخياطة حين تتجه الأوجه إلى الداخل.",
|
||||
"help.surface.revolve": "يدير منحنيات أو مقاطع رسم حول محور ليكوّن سطحًا، بلا أغطية. استخدمه للأغلفة المستديرة مثل أباجورات المصابيح والأوعية والفوهات.",
|
||||
"help.surface.ruled": "ينشئ شريطًا من خطوط مستقيمة ممتدة من سلسلة حواف، باتجاه عمودي الوجه أو مماسه أو بزاوية. استخدمه لجدران الميل وأسطح الامتداد وأسطح الفصل.",
|
||||
"help.surface.stitch": "يخيط أجسامًا سطحية معًا على امتداد حوافها المشتركة، وتصبح جسمًا صلبًا إذا أغلقت. استخدمه لتحويل مجموعة أسطح إلى جسم واحد.",
|
||||
"help.surface.sweep": "يحرّك منحنيات أو مقاطع رسم على امتداد مسار لتكوين سطح، بلا أغطية. استخدمه للمزاريب والأشرطة الزخرفية وسائر الأشكال الرقيقة التي تتبع مسارًا.",
|
||||
"help.surface.thicken": "يمنح جسمًا سطحيًا سماكة ويحوّله إلى جسم صلب. استخدمه لصنع قطع قابلة للطباعة أو التشغيل من الأسطح.",
|
||||
"help.surface.trim": "يقص سطحًا بمستوى أو سطح آخر أو منحنيات رسم، ويبقي الجانب الذي تختاره. استخدمه لقص الأسطح إلى الشكل المطلوب قبل الخياطة.",
|
||||
"help.surface.unstitch": "يفصل أوجه جسم إلى أجسام سطحية مستقلة؛ فيتفكك الجسم الصلب إلى أسطح. استخدمه لإعادة العمل على أوجه مفردة من جسم.",
|
||||
"help.surface.untrim": "يزيل الثقوب من وجه، أو يستعيد حدوده الخارجية إلى الحدود الطبيعية للسطح. استخدمه لاستعادة السطح الكامل بعد القص.",
|
||||
"help.third_party": "رخص الأطراف الثالثة",
|
||||
"help.timeline.compute_all": "يعيد بناء كل ميزة في السجل من البداية. استخدمه لتحديث النموذج ولمعرفة الميزات التي تفشل.",
|
||||
"help.timeline.delete": "يحذف الميزات المحددة من السجل، وحذف رسمٍ يحذف معه الميزات المبنية عليه. استخدمه لإزالة خطوة لم تعد مطلوبة.",
|
||||
"help.timeline.dependents": "يسرد الميزات التي ستُحذف مع ميزة ما، وتلك التي ستفشل بدونها. استخدمه قبل حذف ميزة أو تغييرها.",
|
||||
"help.timeline.play": "أعد تشغيل الميزات المتبقية واحدة تلو الأخرى، مع توقف لمدة نصف ثانية بعد كل إعادة بناء. شغّل هذا الأمر مرة أخرى أو اضغط Escape للإيقاف؛ ينتقل «الذهاب إلى النهاية» فورًا إلى النهاية.",
|
||||
"help.view.apply": "يدير العرض إلى اتجاه قياسي مثل الأمامي أو العلوي أو الأيزومتري، أو إلى عرض مسمّى محفوظ. استخدمه للنظر إلى النموذج من زاوية ثابتة.",
|
||||
"help.view.delete": "يحذف عرضًا مسمّى محفوظًا. لا يتغير النموذج.",
|
||||
"help.view.fit": "يضبط التكبير ويُزيح العرض حتى يملأ النموذج كله أو التحديد منطقة العرض. استخدمه حين يخرج النموذج من مجال الرؤية.",
|
||||
"help.view.grid": "يُظهر الشبكة في منطقة العرض أو يخفيها. استخدمها كدليل للحجم والاتجاه أثناء النمذجة.",
|
||||
"help.view.ground_shadow": "يُظهر ظل النموذج على الأرض أو يخفيه. استخدمه لتقدير الارتفاع والموضع بسهولة أكبر.",
|
||||
"help.view.home": "يعيد العرض إلى الاتجاه الرئيسي ويلائم النموذج. استخدمه للعودة سريعًا إلى عرض معروف.",
|
||||
"help.view.list": "يسرد العروض المسمّاة المحفوظة في التصميم. استخدمه للعثور على عرض حفظته سابقًا.",
|
||||
"help.view.navigate": "يدير العرض أو يُزيحه أو يغيّر تكبيره بخطوات، مثل ربع دورة إلى اليسار. استخدمه لتحريك الكاميرا بدقة بدلًا من السحب.",
|
||||
"help.view.navigation_bar": "يُظهر شريط التنقل أسفل منطقة العرض أو يخفيه. أخفِه لمساحة أكبر، وأظهره للوصول إلى أدوات العرض بالفأرة.",
|
||||
"help.view.rename": "يمنح عرضًا مسمّى محفوظًا اسمًا جديدًا. يبقى العرض نفسه كما هو.",
|
||||
"help.view.save": "يحفظ موضع الكاميرا الحالي كعرض مسمّى في التصميم. استخدمه للعودة إلى الزاوية نفسها لاحقًا، مثلًا للقطات الشاشة.",
|
||||
"help.view.spin": "يدوّر العرض حول النموذج باستمرار حتى النقرة أو المفتاح التالي. استخدمه لعرض النموذج من جميع الجهات.",
|
||||
"help.view.tool": "يثبّت أداة كاميرا، التدوير أو الإزاحة أو التكبير، بحيث يحرّك السحب بزر الفأرة الأيسر العرض حتى توقفها. استخدمه على لوحة اللمس أو بدون زر فأرة أوسط.",
|
||||
"help.view.visual_style": "يبدّل طريقة رسم النموذج: مظلَّل مع الحواف أو بدونها، أو إطار سلكي، أو مع الحواف المخفية. استخدم الإطار السلكي لرؤية الداخل، والمظلَّل لمظهر نظيف.",
|
||||
"history.sketch_under_constrained": "قيود ناقصة ({count} درجات حرية)",
|
||||
"history.sketch_under_constrained_one": "قيود ناقصة ({count} درجة حرية)",
|
||||
"hole_presets.confirm_delete": "تأكيد الحذف",
|
||||
@@ -1592,6 +1874,10 @@
|
||||
"material.selection.mixed": "مواد مختلفة",
|
||||
"measure.at": "عند",
|
||||
"measure.item": "العنصر {number}",
|
||||
"measure.quick_copied": "تم نسخ القياس",
|
||||
"measure.quick_copy": "انقر لنسخ القياس",
|
||||
"measure.quick_edges": "{count} حواف",
|
||||
"measure.quick_faces": "{count} أوجه",
|
||||
"messages.ago_h": "قبل {n} ساعة",
|
||||
"messages.ago_min": "قبل {n} دقيقة",
|
||||
"messages.ago_s": "قبل {n} ث",
|
||||
@@ -1625,6 +1911,7 @@
|
||||
"nav.hfss.help": "Alt مع السحب بالزر الأيسر يُزيح العرض، وShift+Alt مع الأيسر يكبّره، وCtrl مع السحب بالأيسر من مساحة فارغة يدوّره",
|
||||
"nav.inventor.help": "السحب بالزر الأوسط يُزيح العرض، وShift مع الأوسط يدوّره، وCtrl مع الأوسط يكبّره، والسحب بالأيمن يدوّره",
|
||||
"nav.maya.help": "Alt مع السحب بالزر الأيسر يدوّر العرض، وAlt مع الأوسط يُزيحه، وAlt مع الأيمن يكبّره؛ والسحب بالزر الأوسط يُزيح أيضًا",
|
||||
"nav.nx.help": "السحب بالزر الأوسط يدوّر العرض، وShift مع الأوسط يُزيحه (في NX: الأوسط مع الأيمن)، وCtrl مع الأوسط يكبّره (في NX: الأوسط مع الأيسر)؛ والسحب بالأيمن لا يحرك الكاميرا",
|
||||
"nav.openscad.help": "السحب بالزر الأيسر على مساحة فارغة يدوّر العرض، وShift مع السحب بالأيسر يحدد بمربع، وسحب هندسة الرسم يعدّلها؛ والسحب بالأيمن أو الأوسط يُزيح، وShift مع السحب بالأيمن أو الأوسط يكبّر",
|
||||
"nav.perspective.sketch": "تحرير الرسم يستخدم العرض المتعامد. أنهِ الرسم للتبديل إلى المنظور.",
|
||||
"nav.right_drag_orbits.help": "عند الإيقاف: لا يحرّك السحب بالزر الأيمن الكاميرا، ويفتح الزر الأيمن قائمة السياق فقط. اختيار تعيين أزرار الفأرة SolidWorks يوقفه.",
|
||||
@@ -1744,6 +2031,11 @@
|
||||
"not a move": "ليس تحريكًا",
|
||||
"not a number": "ليس عددًا",
|
||||
"open a sketch first": "افتح رسمًا أولًا",
|
||||
"parameters.apply_live": "تطبيق كل تغيير عند مغادرة حقله",
|
||||
"parameters.apply_live_tip": "عند الإيقاف: تنتظر التغييرات حتى «تطبيق» أو «موافق»، ثم يُعاد بناء التصميم مرة واحدة لها جميعًا. «إلغاء» أو Escape يلغيها.",
|
||||
"parameters.held": "{count} تغييرات بانتظار «تطبيق»",
|
||||
"parameters.held_hint": "عدّل التعابير والوحدات. تنتظر التغييرات «تطبيق» أو «موافق».",
|
||||
"parameters.held_one": "تغيير واحد بانتظار «تطبيق»",
|
||||
"parts.automatic_name": "تلقائي",
|
||||
"parts.dimension.across_flats": "مقاس المفتاح",
|
||||
"parts.dimension.bore": "قطر الثقب",
|
||||
@@ -1766,6 +2058,8 @@
|
||||
"parts.family.set_screw": "برغي تثبيت بتجويف سداسي، طرف مسطح",
|
||||
"parts.family.socket_head_cap_screw": "برغي برأس أسطواني بتجويف سداسي",
|
||||
"parts.family.washer": "حلقة مسطحة",
|
||||
"parts.holes": "الثقوب (اختياري)",
|
||||
"parts.placement_hint": "اختر ثقبًا أو أكثر لتثبيت قطعة في كل منها، أو اضغط موافق لوضعها عند نقطة الأصل",
|
||||
"pattern.alignment_2": "المحاذاة 2",
|
||||
"pattern.alignment_hint": "العدد يشمل الأصل. «توسيط» يوازن النسخ؛ و«قلب» يختار الجانب الإضافي عندما يكون العدد زوجيًا.",
|
||||
"pattern.direction_1": "الاتجاه 1",
|
||||
@@ -1818,6 +2112,8 @@
|
||||
"prefs.bottom_centre": "أسفل الوسط",
|
||||
"prefs.bottom_right": "أسفل اليمين",
|
||||
"prefs.browser": "المستعرض",
|
||||
"prefs.browser_eye_left": "أيقونة الإظهار بجانب سهم الطي",
|
||||
"prefs.browser_eye_left_note": "تعرض صفوف المستعرض أيقونة الإظهار/الإخفاء بجانب سهم الطي كما كانت من قبل، بدلًا من عمود عند نهاية الصفوف.",
|
||||
"prefs.browser_reveal_on_hover": "إظهار عند مرور المؤشر",
|
||||
"prefs.browser_show_note": "«ظاهر» يُبقي المستعرض على الشاشة. «إظهار عند مرور المؤشر» يُخفيه حتى يمر المؤشر فوق مكانه أو فوق الشريط الرفيع عند حافته اليسرى، ويبقى مفتوحًا ما دام المؤشر داخله أو كانت قائمة منه مفتوحة.",
|
||||
"prefs.browser_shown": "ظاهر",
|
||||
@@ -1837,6 +2133,8 @@
|
||||
"prefs.ctrl_cmd": "Ctrl / Cmd",
|
||||
"prefs.curved_surfaces": "الأسطح المنحنية",
|
||||
"prefs.curves": "الأسطح المنحنية",
|
||||
"prefs.dark_parts_shading": "الحفاظ على شكل الأجزاء الداكنة",
|
||||
"prefs.dark_parts_shading_help": "تظليل العرض بإضاءة خطية مع إضاءة سماء ناعمة، لتحتفظ الأوجه الداكنة بتدرج بدل أن تصبح سوداء",
|
||||
"prefs.dead_zone_note": "الشريط المخطط هو المنطقة الميتة: تُتجاهل الحركة داخلها.",
|
||||
"prefs.default": "افتراضي",
|
||||
"prefs.design": "افتراضيات التصميم",
|
||||
@@ -1851,6 +2149,8 @@
|
||||
"prefs.edges": "الحواف والتظليل",
|
||||
"prefs.extend": "توسيع",
|
||||
"prefs.extra_navigation": "Ctrl مع السحب بالزر الأيسر في مساحة فارغة يدوّر العرض، واضغط مطولًا على Space للإزاحة.",
|
||||
"prefs.extrude_view_isometric": "التحويل إلى العرض المتساوي القياس عند فتح البثق",
|
||||
"prefs.extrude_view_return": "العودة إلى العرض السابق عند إغلاق البثق",
|
||||
"prefs.follows_os": "يتبع النظام",
|
||||
"prefs.font": "الخط",
|
||||
"prefs.font_fallback": "الرموز التي يفتقدها الخط المختار تُرسم بالخط المدمج، فلا تظهر أي تسمية كمربع فارغ.",
|
||||
@@ -1866,8 +2166,11 @@
|
||||
"prefs.graphics_card_auto": "تلقائي",
|
||||
"prefs.graphics_card_missing": "بطاقة الرسوميات المحفوظة غير متاحة؛ يُستخدم الخيار «تلقائي».",
|
||||
"prefs.graphics_card_restart": "يُطبَّق بعد إعادة تشغيل SolidCraft. يتجاوز WGPU_ADAPTER_NAME هذا الاختيار.",
|
||||
"prefs.graphics_card_unused": "لم تُستخدم بطاقة الرسوميات المحفوظة لهذه النافذة؛ البطاقة المستخدمة تظهر في «المساعدة › حول» وفي شريط الحالة. جرّب «تلقائي»، أو عيّن WGPU_ADAPTER_NAME إلى جزء فريد من اسم البطاقة.",
|
||||
"prefs.graphics_note": "وازن بين السرعة والنعومة. كل خيار يعرض أثره على عيّنة.",
|
||||
"prefs.graphics_presets_note": "الإعدادات المسبقة تضبط الخيارات أدناه معًا.",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out": "إخفاء رموز القيود عند التصغير",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out_note": "تختفي رموز القيود من العرض عندما يُصغَّر الرسم بقدر يجعلها تزحمه. معطّل: تبقى بحجم ثابت على الشاشة عند أي مستوى تكبير.",
|
||||
"prefs.history": "السجل",
|
||||
"prefs.history_origin_bodies": "إظهار الأصل والأجسام في الأعلى",
|
||||
"prefs.history_origin_bodies_note": "يبدأ السجل على اليسار أو تحت المستعرض بمجلد الأجسام للمكوّن النشط وبالأصل، مع أيقونات الإظهار والقوائم كما في المستعرض. لا يتغير السجل في الأسفل.",
|
||||
@@ -1878,6 +2181,8 @@
|
||||
"prefs.history_sketches_note": "عند ضبط الرسومات على «تحت ميزتها»، يعرض السجل على اليسار كل رسم بمستوى واحد للداخل، تحت أول ميزة بُنيت منه، متى كان عريضًا بما يكفي لإظهار الأسماء. أما الخط الزمني في الأسفل فيحتفظ دائمًا بترتيب الإنشاء.",
|
||||
"prefs.history_sketches_under_feature": "تحت ميزتها",
|
||||
"prefs.hold_stop_snapping": "اضغط مطولًا لإيقاف الالتقاط",
|
||||
"prefs.home_fit_size": "حجم العرض الرئيسي والملاءمة",
|
||||
"prefs.home_fit_size_note": "مقدار ما يملؤه النموذج من العرض عندما يُظهره العرض الرئيسي أو الملاءمة أو تصميم مفتوح أو تغيير العرض من متصفح العرض، سواء كان الإعداد أدناه مفعّلًا أم لا. 100 %: يملأ العرض بين اللوحات والبوصلة وشريط التنقل.",
|
||||
"prefs.icons_only": "أيقونات فقط",
|
||||
"prefs.imported_file": "ملف مستورد",
|
||||
"prefs.in_browser": "في المستعرض",
|
||||
@@ -1886,13 +2191,20 @@
|
||||
"prefs.interface_language": "لغة الواجهة",
|
||||
"prefs.interface_note": "شكل SolidCraft وأماكن أجزائه.",
|
||||
"prefs.interval_minutes": "{n} دقيقة",
|
||||
"prefs.invert_navigator_arrows": "عكس أسهم تدوير مكعب العرض",
|
||||
"prefs.invert_navigator_arrows_note": "تدور الأسهم حول المكعب بالكاميرا حسب اتجاه السهم، كما في Fusion وInventor: السهم على اليسار يشير يميناً ويحرّك الكاميرا يميناً. عند الإيقاف: يدور السهم بالمكعب نحو الجهة التي يقع عليها، فيحرّك سهم اليسار الكاميرا يساراً. لا يتأثر سهما التدوير المنحنيان.",
|
||||
"prefs.keep_work_on_tab_switch": "إبقاء مربعات الحوار والأدوات مفتوحة عند التبديل بين التصاميم",
|
||||
"prefs.keep_work_on_tab_switch_note": "تحتفظ كل علامة تبويب تصميم بمربع الحوار أو الأداة المفتوحة، بما حددته وكتبته فيها، وبعلامة تبويب شريط الأدوات. وتجدها كما هي عند العودة إلى التصميم. عند الإيقاف: يؤدي التبديل بين التصاميم إلى إلغائها وعرض علامة التبويب «النموذج».",
|
||||
"prefs.labels": "التسميات",
|
||||
"prefs.language_system": "لغة النظام",
|
||||
"prefs.layout": "التخطيط",
|
||||
"prefs.layout_note": "المضغوط يثبّت اللوحات على حواف النافذة. شفافية المستعرض متاحة في الوضع العائم. غيّر جهة المساعد من صفحة المساعد.",
|
||||
"prefs.left": "يسار",
|
||||
"prefs.left_click": "نقر أيسر",
|
||||
"prefs.line_drag_draws_one": "الضغط والسحب يرسم خطًا واحدًا",
|
||||
"prefs.line_drag_draws_one_note": "في أداة الخط، الضغط ثم السحب ثم الإفلات يرسم خطًا واحدًا من نقطة الضغط إلى نقطة الإفلات وينتهي هناك. لا تزال النقرات ترسم سلسلة. عند الإيقاف: يضع السحب نقطة حيث يُفلت، كما تفعل النقرة.",
|
||||
"prefs.line_hover_tangent_arc": "التوقف عند آخر نقطة في الخط للتبديل إلى قوس مماسي",
|
||||
"prefs.line_hover_tangent_arc_note": "في أداة الخط، بعد رسم قطعة، ابتعد عن آخر نقطة في السلسلة ثم عد إليها وأبقِ المؤشر ثابتًا عليها: تحدد النقرة التالية نهاية قوس مماسي، والحركة نفسها تعيدك إلى الخطوط. عند الإيقاف: لا يحدث شيء عند التوقف هناك.",
|
||||
"prefs.linked_designs": "التصاميم المرتبطة",
|
||||
"prefs.live_input": "الإدخال المباشر",
|
||||
"prefs.live_preview": "المعاينة المباشرة",
|
||||
@@ -1906,6 +2218,9 @@
|
||||
"prefs.max_file_size_step": "ملفات STEP والاستيراد",
|
||||
"prefs.max_file_size_web": "يفتح تطبيق الويب ملفات STEP والاستيراد حتى 512 MB والتصاميم حتى 256 MB؛ لا يتسع تبويب المتصفح لملفات أكبر. يمكن رفع هذه الحدود في تطبيق سطح المكتب.",
|
||||
"prefs.megabytes": "MB",
|
||||
"prefs.menu_grid": "أيقونات كبيرة",
|
||||
"prefs.menu_list": "قائمة",
|
||||
"prefs.menus": "القوائم",
|
||||
"prefs.minutes": "دقائق",
|
||||
"prefs.minutes_suffix": " دقيقة",
|
||||
"prefs.mouse": "الفأرة ولوحة اللمس",
|
||||
@@ -1913,6 +2228,8 @@
|
||||
"prefs.mouse_mapping": "تعيين أزرار الفأرة",
|
||||
"prefs.navigation": "التنقل",
|
||||
"prefs.navigation_note": "كيف تحرك الفأرة ولوحة اللمس والفأرة ثلاثية الأبعاد العرض.",
|
||||
"prefs.navigator_fit": "ملاءمة النموذج بعد تغيير العرض من متصفح العرض",
|
||||
"prefs.navigator_fit_note": "النقر على وجه أو ركن أو سهم في المكعب، أو على محور في أداة المحاور، يوجّه العرض أيضًا نحو منتصف النموذج من المسافة الواحدة التي تُظهره كاملًا من كل جهة (كرته المحيطة). يستخدم العرض الرئيسي التكبير والمركز ذاتهما ما دام هذا مفعّلًا، فلا تغيّر العروض المختارة بعده سوى الاتجاه. عند الإيقاف: يدور العرض في مكانه محتفظًا بالهدف والتكبير.",
|
||||
"prefs.network_host_remove": "إزالة",
|
||||
"prefs.network_locations": "السماح بمواقع الشبكة في التصاميم",
|
||||
"prefs.network_locations_note": "عند الإيقاف: الملفات المرتبطة بالتصميم على حاسوب آخر (\\\\server\\share) لا تُفتح إلا من الخوادم المدرجة هنا، أو بعد أن تسمح لأحدها عند السؤال.",
|
||||
@@ -1925,10 +2242,16 @@
|
||||
"prefs.origin_plane_names": "أسماء مستويات الأصل",
|
||||
"prefs.origin_plane_names_note": "الأسماء المعروضة في المستعرض والحوارات والقوائم. {top} هو XY و{front} هو XZ و{right} هو YZ، والمحور Z للأعلى. تحتفظ الأوامر والسكربتات والتصاميم المحفوظة بـ XY وXZ وYZ.",
|
||||
"prefs.overall_speed": "السرعة العامة",
|
||||
"prefs.parameter_list_rows": "صفوف قائمة المعاملات",
|
||||
"prefs.parameter_list_rows_tip": "يعرض السهم لأسفل في حقل قيمة فارغ المعاملات، المفضلة أولًا، حتى هذا العدد. العدد الأقل يبقي القائمة خفيفة في التصميم الكبير.",
|
||||
"prefs.persistent_ribbon_pressed": "تمييز أوامر الشريط النشطة",
|
||||
"prefs.persistent_ribbon_pressed_help": "تمييز أوامر الشريط أثناء تفعيل تأثيراتها. أوقف هذا الخيار للاحتفاظ بالمظهر المحايد السابق ومساعدة الأوامر.",
|
||||
"prefs.perspective_fov": "مجال الرؤية",
|
||||
"prefs.placement": "الموضع",
|
||||
"prefs.prefer_free_sketch_points": "تفضيل نقاط الرسم القابلة للتحريك عند تداخل النقاط",
|
||||
"prefs.preview_choices": "معاينة اختياراتك",
|
||||
"prefs.print_face_highlight": "إبراز وجه الطباعة",
|
||||
"prefs.print_face_highlight_tip": "مدى قوة تلوين وجه الطباعة للجسم ورسم حدوده في العرض. القيمة 0 % لا تُظهر أي إبراز.",
|
||||
"prefs.profile_active": "ملف التعريف النشط",
|
||||
"prefs.profile_applied": "تم تطبيق ملف التعريف.",
|
||||
"prefs.profile_changed": "تغيّرت الإعدادات منذ حفظ ملف التعريف. «حفظ» يحفظها فيه.",
|
||||
@@ -1950,9 +2273,13 @@
|
||||
"prefs.quality_fastest": "الأسرع",
|
||||
"prefs.quality_slowest": "الأبطأ",
|
||||
"prefs.quality_smoother": "أنعم",
|
||||
"prefs.quick_measure": "قياس سريع في زاوية العرض",
|
||||
"prefs.quick_measure_note": "مقاس العناصر المحددة في الزاوية اليمنى السفلية من العرض: طول الحافة (أو Ø وR للحافة الدائرية)، ومساحة الوجه، وموضع النقطة، والمسافة والزاوية بين عنصرين، ومجموع عدة حواف أو أوجه. النقر ينسخه.",
|
||||
"prefs.render_previous_geometry_budget": "استخدام ميزانية الهندسة السابقة لمعاينة التصيير",
|
||||
"prefs.render_previous_geometry_budget_help": "استعادة حد الهندسة الثابت السابق (512 ميبيبايت على سطح المكتب 64 بت، و128 ميبيبايت على المنصات الأخرى) بدلًا من الميزانية المعتمدة على الجهاز.",
|
||||
"prefs.reports_saved": "{n} محفوظة",
|
||||
"prefs.ribbon_click_ends_tool": "النقر على زر الأداة قيد التشغيل ينهيها",
|
||||
"prefs.ribbon_click_ends_tool_note": "النقر على زر الشريط المضيء لأداة الرسم المستخدمة ينهي الأداة، فيعود النقر في العرض إلى التحديد. عند الإيقاف: يبدأ النقر الأداة من جديد.",
|
||||
"prefs.ribbon_reveal": "إظهار مكان نتائج البحث في الشريط",
|
||||
"prefs.ribbon_reveal_note": "عند تمرير المؤشر فوق نتيجة في «البحث في الأوامر» يظهر مكان الأمر في الشريط: تبويبه أو زره أو صفه في القائمة المنسدلة للوحة. ويومض هناك الأمر الذي بدأ من البحث، ويُعلِّم الأمر الجاري من قائمة منسدلة لوحتَه.",
|
||||
"prefs.right_click": "نقر أيمن",
|
||||
@@ -1963,6 +2290,8 @@
|
||||
"prefs.search_empty": "لا توجد إعدادات مطابقة",
|
||||
"prefs.select": "تحديد",
|
||||
"prefs.select_one_item": "تحديد عنصر واحد",
|
||||
"prefs.select_other_hidden": "تحديد العناصر الهندسية المخفية باستخدام «تحديد عنصر آخر»",
|
||||
"prefs.select_other_hidden_help": "عند التفعيل: تضمين الأجسام والمخططات المخفية والحواف المحجوبة قرب المؤشر. عند التعطيل: استخدام القائمة الأصلية للعناصر الهندسية المرئية أسفل المؤشر.",
|
||||
"prefs.selecting": "التحديد",
|
||||
"prefs.shift": "Shift",
|
||||
"prefs.shift_add_ctrl_toggle": "Shift يضيف فقط، وCtrl / Cmd يبدّل",
|
||||
@@ -1974,11 +2303,18 @@
|
||||
"prefs.sketch_align_points_note": "أثناء الرسم، تتحاذى النقطة أفقيًا مع نقطة رسم وعموديًا مع نقطة أخرى في الوقت نفسه، مع خط إرشادي منقط، وتحتفظ النقرة بالمحاذاتين. عند الإيقاف: مع النقطة السابقة فقط، محور واحد في كل مرة.",
|
||||
"prefs.sketch_conflict_colour": "الهندسة المتعارضة بلون التعارض",
|
||||
"prefs.sketch_conflict_colour_note": "عندما تتعارض قيود الرسم، تُرسم المنحنيات والنقاط التي يمسكها قيد فاشل بلون التعارض أيضًا، لا رمزه أو بُعده فقط. عند الإيقاف: تحتفظ بألوانها المعتادة.",
|
||||
"prefs.sketch_construction_lines": "أدوات الخطوط الإنشائية الموسعة",
|
||||
"prefs.sketch_exit_view": "عند انتهاء الرسم",
|
||||
"prefs.sketch_exit_view.keep": "إبقاء العرض الحالي",
|
||||
"prefs.sketch_exit_view.previous": "العودة إلى العرض السابق",
|
||||
"prefs.sketch_exit_view.unless_rotated": "العودة ما لم يُدوَّر العرض",
|
||||
"prefs.sketch_exit_view_note": "أين ينتقل العرض بعد إنهاء الرسم أو الإلغاء أو الضغط على Esc مرتين.",
|
||||
"prefs.sketch_face_activates_part": "الرسم على وجه جزء يجعل ذلك الجزء نشطًا",
|
||||
"prefs.sketch_face_activates_part_note": "الرسم الذي يبدأ على وجه جسم في مكوّن آخر ينشّط ذلك المكوّن أولًا، فينتمي الرسم إليه ويبقى مع ذلك الجزء في المستعرض. ويبقى الجزء نشطًا بعد ذلك. عند الإيقاف: ينتمي الرسم إلى المكوّن النشط.",
|
||||
"prefs.sketch_open_look_at": "توجيه العرض نحو الرسم عند فتحه",
|
||||
"prefs.sketch_open_look_at_note": "عند الإيقاف: إنشاء الرسم أو تحريره يُبقي العرض كما هو. يوجّه «النظر إلى» العرض نحو الرسم عند الحاجة.",
|
||||
"prefs.sketch_recent_snap": "الالتقاط التلقائي إلى المراكز ونقاط المنتصف الأخيرة",
|
||||
"prefs.sketch_recent_snap_note": "أثناء الرسم، يلتقط المؤشر الموضع الذي يتقاطع فيه دليلا آخر مركزي دائرتين أو نقطتي منتصف حافتين مستقيمتين. عند الإيقاف: تبقى تلك الأدلة للعرض فقط ولا يتحرك المؤشر.",
|
||||
"prefs.sketch_selection": "الرسم والتحديد",
|
||||
"prefs.sketch_selection_heading": "الرسم والتحديد",
|
||||
"prefs.sketch_selection_note": "كيف تلتقط الرسومات وكيف تحدد النقرات.",
|
||||
@@ -1988,6 +2324,8 @@
|
||||
"prefs.sketch_tab_always_note": "يبقى تبويب الرسم في الشريط بعد تبويب النموذج مباشرة حتى عندما لا يكون أي رسم مفتوحًا. عندها تبدأ أدوات الرسم فيه رسمًا على المستوي أو الوجه المحدد، أو على المستوي الذي تختاره بعد ذلك، وتكون الأداة جاهزة فيه.",
|
||||
"prefs.sketch_tracking_guides": "أدلة محاذاة المراكز ونقاط المنتصف",
|
||||
"prefs.sketch_tracking_guides_note": "مرّر المؤشر فوق مركز دائرة أو نقطة منتصف حافة مستقيمة، ثم حرّكه أفقيًا أو عموديًا لإظهار دليل منقّط مؤقت.",
|
||||
"prefs.sketch_tracking_points": "أدلة محاذاة من نقاط النهاية والزوايا أثناء الرسم",
|
||||
"prefs.sketch_tracking_points_note": "عندما تنتظر أداة رسم نقطة، يؤدي تمرير المؤشر فوق نهاية خط أو قوس أو زاوية مستطيل أو نقطة حرة إلى إظهار الدليل المنقّط المؤقت نفسه الذي يظهر للمركز أو نقطة المنتصف. عند الإيقاف: المراكز ونقاط المنتصف فقط.",
|
||||
"prefs.sketching": "الرسم",
|
||||
"prefs.snap_drawing_note": "أثناء الرسم أو سحب نقطة في الرسم.",
|
||||
"prefs.source": "المصدر",
|
||||
@@ -2004,6 +2342,24 @@
|
||||
"prefs.status_error": "خطأ",
|
||||
"prefs.status_selected": "محدد",
|
||||
"prefs.status_warning": "تحذير",
|
||||
"prefs.structure.appearance": "المظهر",
|
||||
"prefs.structure.appearance_note": "الألوان والنصوص وإمكانية الوصول.",
|
||||
"prefs.structure.in_profile": "ضمن ملف التعريف",
|
||||
"prefs.structure.layout": "التخطيط",
|
||||
"prefs.structure.layout_note": "مواضع أجزاء النافذة.",
|
||||
"prefs.structure.look": "المظهر",
|
||||
"prefs.structure.measure_pointer": "القياس والمؤشر",
|
||||
"prefs.structure.mouse3d": "فأرة ثلاثية الأبعاد",
|
||||
"prefs.structure.mouse3d_note": "SpaceMouse وSpaceNavigator.",
|
||||
"prefs.structure.navigation_note": "الفأرة ولوحة اللمس. للفأرة ثلاثية الأبعاد صفحة خاصة بها.",
|
||||
"prefs.structure.profile": "ملف التعريف",
|
||||
"prefs.structure.profile_edited": "تغيّر منذ الحفظ",
|
||||
"prefs.structure.profile_hover": "محفوظ في ملفات تعريف الإعدادات",
|
||||
"prefs.structure.scale_percent": "{percent}%",
|
||||
"prefs.structure.sketch": "رسم",
|
||||
"prefs.structure.tools": "الأدوات",
|
||||
"prefs.structure.tools_note": "كيفية عمل أدوات النمذجة.",
|
||||
"prefs.structure.work": "العمل",
|
||||
"prefs.supersampling_brief": "يرسم العرض بحجم أكبر ثم يصغّره: حاد جدًا لكنه أثقل.",
|
||||
"prefs.tab_accent_note": "لون التمييز يتبع التبويب النشط",
|
||||
"prefs.theme_file": "ملف السمة",
|
||||
@@ -2015,6 +2371,16 @@
|
||||
"prefs.theme_follow_off": "إيقاف",
|
||||
"prefs.theme_follow_stop": "إيقاف الاتباع",
|
||||
"prefs.theme_import_hint": "انقر لاختيار ملف سمة، أو أفلت ملفًا هنا، أو اضغط Ctrl+V (Cmd+V على Mac) بعد نسخ سمة",
|
||||
"prefs.theme_option_opacity": "العتامة",
|
||||
"prefs.theme_option_opacity_help": "اضبط عتامة اللوحات العائمة. يُطبّق حد أدنى للعتامة للحفاظ على وضوح النص فوق ألوان منطقة العرض.",
|
||||
"prefs.theme_option_tab_colours": "ألوان علامات التبويب",
|
||||
"prefs.theme_option_tab_colours_help": "استخدم ألوان اللوحات ومنطقة العرض من هذه السمة لكل علامة تبويب في الشريط.",
|
||||
"prefs.theme_option_tab_fade_ms": "انتقال علامات التبويب",
|
||||
"prefs.theme_option_tab_fade_ms_help": "تتغيّر ألوان اللوحات ومنطقة العرض تدريجيًا عند تبديل علامات التبويب. القيمة صفر تبدّلها فورًا.",
|
||||
"prefs.theme_options_badge": "الخيارات",
|
||||
"prefs.theme_options_more": "المزيد · {count}",
|
||||
"prefs.theme_options_reset": "إعادة تعيين",
|
||||
"prefs.theme_options_unavailable": "غير متاح على هذا الجهاز",
|
||||
"prefs.theme_paste": "لصق السمة",
|
||||
"prefs.theme_paste_none": "لا تحتوي الحافظة على سمة SolidCraft",
|
||||
"prefs.timeline_half_hour": "−30 دقيقة",
|
||||
@@ -2036,13 +2402,23 @@
|
||||
"prefs.under_cursor": "تحت المؤشر",
|
||||
"prefs.units_precision": "الوحدات والدقة",
|
||||
"prefs.updates": "التحديثات",
|
||||
"prefs.value_boxes_in_view": "إظهار القيم بجانب مقابضها في العرض",
|
||||
"prefs.value_boxes_in_view_tip": "قيمة الأمر (المسافة، نصف القطر…) في مربع بجانب مقبضه، فوق النموذج. عند الإيقاف: تكتبها في نافذة الأمر، التي تتلقى لوحة المفاتيح بعد التحديد، ولا شيء يغطي النموذج.",
|
||||
"prefs.view": "سلوك العرض",
|
||||
"prefs.view_confirm_corner": "موافق وإلغاء في زاوية العرض",
|
||||
"prefs.view_confirm_corner_note": "أثناء فتح مربع حوار أو رسم، تؤدي علامة الصح وعلامة الإكس أعلى يمين العرض ما يؤديه زرّا موافق وإلغاء في مربع الحوار، أو تنهي الرسم وتلغيه. وينتقل متصفح العرض إلى أسفلهما.",
|
||||
"prefs.viewport": "منطقة العرض",
|
||||
"prefs.viewport_analysis_status": "إظهار حالة التحليل في منطقة العرض",
|
||||
"prefs.viewport_analysis_status_help": "عرض التحليلات النشطة أعلى منطقة العرض، وفتح مفتاح الألوان لكل تحليل من عنصره، واستخدام Esc لإيقاف أحدث تحليل. أوقف الخيار لاستعادة مفاتيح الألوان في الزاوية وسلوك Esc السابق.",
|
||||
"prefs.viewport_background": "الخلفية",
|
||||
"prefs.viewport_background_colour": "لون",
|
||||
"prefs.viewport_background_theme": "تدرج السمة",
|
||||
"prefs.viewport_section_status": "إظهار حالة المقطع في منطقة العرض",
|
||||
"prefs.viewport_section_status_help": "عرض إعداد المقطع في منطقة العرض. يُوقف Escape وزر الشريط النشط المقطع. عطّل الخيار للاحتفاظ بأدوات المقطع السابقة.",
|
||||
"prefs.viewport_status_details": "تفاصيل منطقة العرض المباشرة",
|
||||
"prefs.viewport_status_details_help": "حرّر إعدادات التحليل والمقطع النشطين في بطاقات التفاصيل القياسية. عطّل هذا الخيار لاستعادة مفاتيح ألوان التحليل للقراءة فقط ومربع حوار المقطع.",
|
||||
"prefs.viewport_status_summary": "تلخيص عناصر حالة منطقة العرض",
|
||||
"prefs.viewport_status_summary_help": "اجمع ثلاثة عناصر أو أكثر لحالة منطقة العرض في شارة ملخّصة واحدة. عطّل الخيار لإبقاء كل عنصر في الصف الكامل.",
|
||||
"prefs.wheel": "العجلة",
|
||||
"prefs.wheel_trackpad": "العجلة ولوحة اللمس",
|
||||
"prefs.workspace": "مساحة العمل",
|
||||
@@ -2052,6 +2428,10 @@
|
||||
"properties.title": "الخصائص: {name}",
|
||||
"recovery.days_ago": "قبل {count} يوم",
|
||||
"recovery.detail": "{file} · {features} ميزة · حُفظ تلقائيًا {when}",
|
||||
"recovery.discard_all": "تجاهل الكل",
|
||||
"recovery.discard_all_detail": "لا يمكن التراجع عن هذا الإجراء.",
|
||||
"recovery.discard_all_title": "تجاهل {count} من عمليات الحفظ التلقائي؟",
|
||||
"recovery.discard_all_title_one": "تجاهل حفظ تلقائي واحد؟",
|
||||
"recovery.hours_ago": "قبل {count} ساعة",
|
||||
"recovery.just_now": "الآن",
|
||||
"recovery.min_ago": "قبل {count} دقيقة",
|
||||
@@ -2917,7 +3297,9 @@
|
||||
"render.output_ready": "جاهز للتصيير",
|
||||
"render.output_run_check": "تشغيل الفحص",
|
||||
"render.output_size_limit": "{method}: حتى {dimension} بكسل لكل ضلع و{pixels} بكسل. أكبر حجم مناسب: {width} × {height}.",
|
||||
"render.output_size_method_profile": "لتصيير {width} × {height}، اختر {method} مع ملف موارد CPU «{profile}»، أو حجمًا أصغر.",
|
||||
"render.output_size_ok": "الحجم مناسب · {width} × {height} بكسل",
|
||||
"render.output_size_profile": "لتصيير {width} × {height}، اختر ملف موارد CPU «{profile}»، أو حجمًا أصغر.",
|
||||
"render.output_swap_orientation": "تبديل العرض والارتفاع",
|
||||
"render.output_tools_inspector": "عدّل الحجم والصيغة في مفتش المخرجات.",
|
||||
"render.output_view_image": "عرض الصورة",
|
||||
@@ -3130,6 +3512,7 @@
|
||||
"render.size_custom": "مخصص…",
|
||||
"render.size_full_hd": "Full HD",
|
||||
"render.size_hd": "HD",
|
||||
"render.size_needs_profile": "{size} · يتطلب «{profile}»",
|
||||
"render.size_presets": "إعدادات الحجم المسبقة",
|
||||
"render.size_presets_pending": "تصل مع محرر المخرجات",
|
||||
"render.size_preview": "معاينة",
|
||||
@@ -3417,6 +3800,24 @@
|
||||
"sheet.flange_type_contour": "محيط",
|
||||
"sheet.flange_type_edge": "حافة",
|
||||
"sheet.no_body": "لا يوجد جسم صفائح معدنية: ابدأ واحدًا من حافة مثنية > أساسية، أو حوّل لوحًا إلى صفائح معدنية بأمر تحويل إلى صفائح معدنية (اختر وجهه المسطح الكبير)",
|
||||
"sheet.personal_rules.confirm_delete": "تأكيد الحذف",
|
||||
"sheet.personal_rules.delete": "حذف",
|
||||
"sheet.personal_rules.delete_prompt": "هل تحذف هذه القاعدة الشخصية؟ القواعد الموجودة في التصاميم لا تتغير.",
|
||||
"sheet.personal_rules.full": "المكتبة الشخصية فيها 64 قاعدة بالفعل.",
|
||||
"sheet.personal_rules.invalid_name": "أدخل اسمًا قصيرًا بلا فواصل أسطر ولا محارف تحكم.",
|
||||
"sheet.personal_rules.invalid_values": "أكمل قيم القاعدة: يجب أن تُحسب كل قيمة في هذا التصميم، بسماكة موجبة ومعامل K من 0 إلى 1.",
|
||||
"sheet.personal_rules.missing": "القاعدة الشخصية المحددة لم تعد متاحة.",
|
||||
"sheet.personal_rules.name": "اسم القاعدة",
|
||||
"sheet.personal_rules.name_exists": "توجد قاعدة شخصية بهذا الاسم. استخدم اسمًا آخر.",
|
||||
"sheet.personal_rules.name_hint": "اسم فريد",
|
||||
"sheet.personal_rules.overwrite": "حفظ التغييرات في القاعدة الشخصية المحددة",
|
||||
"sheet.personal_rules.rename": "إعادة تسمية",
|
||||
"sheet.personal_rules.rule": "القاعدة الشخصية",
|
||||
"sheet.personal_rules.save": "حفظ كجديدة",
|
||||
"sheet.personal_rules.scope": "محفوظة في ملفك الشخصي لكل التصاميم.",
|
||||
"sheet.personal_rules.select": "اختر قاعدة",
|
||||
"sheet.personal_rules.title": "القواعد الشخصية",
|
||||
"sheet.personal_rules.unsupported": "تحتوي هذه القاعدة على قيم لا يستطيع هذا الإصدار استخدامها.",
|
||||
"shortcut.json_error": "يجب أن تكون المعاملات بصيغة JSON: {error}",
|
||||
"shortcut.no_command": "لا يوجد أمر `{id}`، ويجب أن يكون النص قبل JSON معرّف أمر",
|
||||
"shortcut.pin": "تثبيت في أعلى مربع S",
|
||||
@@ -3453,8 +3854,10 @@
|
||||
"sketch_text.align_right": "يمين",
|
||||
"sketch_text.bold": "غامق",
|
||||
"sketch_text.builtin_font": "{family} (مدمج)",
|
||||
"sketch_text.formula": "ابدأ بـ = لتكوين النص من المعاملات: ='W' + number(Width)",
|
||||
"sketch_text.italic": "مائل",
|
||||
"sketch_text.loading_fonts": "جارٍ البحث عن الخطوط المثبتة…",
|
||||
"sketch_text.no_bold": "الخط المدمج لا يحتوي على نمط غامق: اختر خطًا مثبتًا",
|
||||
"sketch_text.on_path": "النص يتبع مساره: المنحنى يحدد موضعه",
|
||||
"sketch_text.path_clear": "فصل النص عن منحناه",
|
||||
"sketch_text.path_hint": "منحنى من الرسم يتبعه النص: انقر هنا ثم على المنحنى",
|
||||
@@ -3593,6 +3996,8 @@
|
||||
"ui.3d_mouse_section": "الفأرة ثلاثية الأبعاد",
|
||||
"ui.3d_mouse_show_in_view": "إظهار الفأرة ثلاثية الأبعاد في العرض ثلاثي الأبعاد",
|
||||
"ui.3d_mouse_show_in_view_tip": "صورة للفأرة ثلاثية الأبعاد في الزاوية السفلية اليسرى، تتحرك كلما حرّكتها.",
|
||||
"ui.3d_mouse_sketch_orbit": "تدوير الرسومات بالفأرة ثلاثية الأبعاد",
|
||||
"ui.3d_mouse_sketch_orbit_tip": "تدير الفأرة ثلاثية الأبعاد العرض أيضًا أثناء فتح رسم ورؤيته من الأمام مباشرة، كما تفعل الفأرة. عند الإيقاف: تُزيح الرسم وتكبّره فقط حتى تُميل العرض.",
|
||||
"ui.3d_mouse_skip": "جهازي لا يستطيع ذلك",
|
||||
"ui.3d_mouse_skip_tip": "يتخطى هذه الحركة في الاتجاهين، وتستبعدها المعايرة.",
|
||||
"ui.3d_mouse_speed": "سرعة الفأرة ثلاثية الأبعاد",
|
||||
@@ -3621,6 +4026,8 @@
|
||||
"ui.3d_mouse_step_twist_counterclockwise": "لُفّ الغطاء عكس عقارب الساعة، وأمسكه، ثم اتركه.",
|
||||
"ui.3d_mouse_switch_cap": "المعايرة كجهاز العودة إلى المركز",
|
||||
"ui.3d_mouse_switch_trackball": "المعايرة ككرة تتبّع",
|
||||
"ui.3d_mouse_use_direct": "المشغل المباشر",
|
||||
"ui.3d_mouse_use_direct_tip": "قراءة الفأرة ثلاثية الأبعاد مباشرة (hidraw) بدلًا من المرور عبر spacenavd.",
|
||||
"ui.3d_mouse_view_axis": "محور العرض",
|
||||
"ui.3d_mouse_view_off": "متوقف",
|
||||
"ui.3d_mouse_view_off_tip": "ملف تعريف مشغّل الفأرة ثلاثية الأبعاد يوقف هذا المحور، فلا تحرك حركتُه العرض. اختيار حركة محور آخر هنا يبادل بينهما، فتتوقف تلك الحركة عن تحريك العرض.",
|
||||
@@ -3659,6 +4066,7 @@
|
||||
"ui.agent_chat_auth_terminal": "شغّل هذا في الطرفية، ثم اضغط «اتصال» مرة أخرى:",
|
||||
"ui.agent_chat_auth_title": "تسجيل الدخول إلى الوكيل",
|
||||
"ui.agent_chat_cancel": "إلغاء",
|
||||
"ui.agent_chat_cannot_start": "مثبّت، لكنه لا يبدأ: {error}",
|
||||
"ui.agent_chat_changes": "التغييرات: {n}، خطوة تراجع واحدة",
|
||||
"ui.agent_chat_changes_n": "{n} تغييرات",
|
||||
"ui.agent_chat_changes_of": "{n}/{limit} تغييرات",
|
||||
@@ -3751,9 +4159,12 @@
|
||||
"ui.agent_chat_queued_stopped": "في الانتظار (متوقف، لم يُرسل)",
|
||||
"ui.agent_chat_refresh": "تحديث",
|
||||
"ui.agent_chat_refused": "غير مسموح للوكيل: {reason}",
|
||||
"ui.agent_chat_reinstall": "{agent} مثبّت ({program})، لكنه لم يبدأ عندما فحصه SolidCraft: {error}\nقد يكون تثبيته غير مكتمل، أو مُعدًّا لنوع آخر من الحواسيب. ثبّته من جديد بالأمر `{install}`، وتحقّق من أنه يعرض رقم إصداره في الطرفية، ثم اضغط تحديث.",
|
||||
"ui.agent_chat_remove": "إزالة من قائمة الانتظار",
|
||||
"ui.agent_chat_remove_file": "إزالته من هذه الرسالة",
|
||||
"ui.agent_chat_remove_imported": "إزالته من هذه الرسالة؛ تبقى القطعة في التصميم (التراجع يزيلها)",
|
||||
"ui.agent_chat_reply_cut_off": "بلغ الرد حد طوله قبل أن يكتمل، لذا قد يكون ناقصًا. اطلب من الوكيل أن يتابع، أو أن يجيب بإيجاز أكبر.",
|
||||
"ui.agent_chat_reply_declined": "رفض النموذج الإجابة عن هذه الرسالة.",
|
||||
"ui.agent_chat_retry": "إعادة المحاولة",
|
||||
"ui.agent_chat_right": "يمين",
|
||||
"ui.agent_chat_save": "حفظ",
|
||||
@@ -3812,12 +4223,17 @@
|
||||
"ui.ai_copy_suffix": "نسخة",
|
||||
"ui.ai_custom_url": "عنوان URL مخصص",
|
||||
"ui.ai_default": "الافتراضي",
|
||||
"ui.ai_edit": "تعديل",
|
||||
"ui.ai_edit_agent_title": "تعديل الوكيل",
|
||||
"ui.ai_edit_gone": "أُزيل هذا الوكيل، لذا لا يوجد ما يُحفظ.",
|
||||
"ui.ai_edit_tip": "غيّر اسم هذا الوكيل أو أمره أو نقطة الاتصال الخاصة به. يبقى المفتاح المحفوظ مخفيًا.",
|
||||
"ui.ai_http_busy": "نقطة النهاية مشغولة أو تجاوزت حدها؛ حاول لاحقًا",
|
||||
"ui.ai_http_key": "رفضت نقطة النهاية المفتاح: تحقق منه في التفضيلات › الذكاء الاصطناعي",
|
||||
"ui.ai_http_not_found": "لا توجد نقطة نهاية أو نموذج بهذا الاسم: تحقق من عنوان URL الأساسي واسم النموذج",
|
||||
"ui.ai_http_too_large": "المحادثة أكبر من أن تقبلها نقطة النهاية هذه؛ ابدأ محادثة جديدة",
|
||||
"ui.ai_key": "مفتاح API",
|
||||
"ui.ai_key_hint": "اختياري؛ يُحفظ في سلسلة مفاتيح النظام",
|
||||
"ui.ai_key_keep_hint": "اتركه فارغًا للإبقاء على المفتاح المحفوظ",
|
||||
"ui.ai_key_needs_https": "لا يُرسل المفتاح إلا عبر HTTPS أو إلى هذا الحاسوب.",
|
||||
"ui.ai_key_note": "يُخزّن في سلسلة مفاتيح النظام، وليس في إعدادات SolidCraft أبدًا. اتركه فارغًا لخادم محلي.",
|
||||
"ui.ai_keychain_error": "رفضت سلسلة مفاتيح النظام: {error}",
|
||||
@@ -3844,11 +4260,15 @@
|
||||
"ui.ai_permissions": "الأذونات",
|
||||
"ui.ai_preset": "إعداد مسبق",
|
||||
"ui.ai_protocol": "البروتوكول",
|
||||
"ui.ai_reasoning_effort": "مستوى الاستدلال",
|
||||
"ui.ai_reasoning_effort_field_hint": "فارغ = الافتراضي للمزوّد",
|
||||
"ui.ai_reasoning_effort_hint": "اختياري. يُرسل إلى نقطة النهاية على أنه `reasoning_effort`؛ تختلف القيم المقبولة حسب المزوّد (مثل `low` أو `high` أو `max`). لا تستبدل SolidCraft القيمة التي تحددها هنا أبدًا. اتركه فارغًا لعدم إرسال شيء والاحتفاظ بالافتراضي للمزوّد.",
|
||||
"ui.ai_remove": "إزالة",
|
||||
"ui.ai_request_timed_out": "استغرق النموذج أكثر من {seconds} ثانية. يمكنك رفع مهلة الطلب لنقطة النهاية هذه من التفضيلات › المساعد.",
|
||||
"ui.ai_request_timeout": "مهلة الطلب",
|
||||
"ui.ai_request_timeout_hint": "المدة التي يمكن أن يستغرقها طلب واحد للنموذج إلى نقطة النهاية هذه، من 30 ثانية إلى ساعة. ارفعها للنماذج المحلية البطيئة.",
|
||||
"ui.ai_reset": "إعادة تعيين",
|
||||
"ui.ai_save": "حفظ",
|
||||
"ui.ai_settings": "إعدادات الذكاء الاصطناعي…",
|
||||
"ui.ai_show_features": "إظهار ميزات الذكاء الاصطناعي",
|
||||
"ui.ai_show_features_note": "محادثة الوكيل: لوحة يعمل فيها وكيل برمجي تستخدمه أصلًا، أو نقطة نهاية نموذج تختارها، على التصميم المفتوح. عند الإيقاف: لا زر ولا اختصار ولا عنصر قائمة ولا لوحة للذكاء الاصطناعي، ولا يُبحث عن شيء أو يُشغّل.",
|
||||
@@ -3937,6 +4357,7 @@
|
||||
"ui.circle": "دائرة",
|
||||
"ui.circular_pattern": "نمط دائري",
|
||||
"ui.clear": "مسح",
|
||||
"ui.clear_print_face": "مسح وجه الطباعة",
|
||||
"ui.clear_recent": "مسح الأخيرة",
|
||||
"ui.clear_the_selection": "مسح التحديد",
|
||||
"ui.click_selects_whole_bodies": "النقر يحدد الأجسام كاملة",
|
||||
@@ -3971,6 +4392,15 @@
|
||||
"ui.constant": "ثابت",
|
||||
"ui.constraints_conflict": "تعارض في القيود",
|
||||
"ui.construction": "مساعد",
|
||||
"ui.construction.angle_hint": "خط إنشائي: انقر نقطة ثم أدخل زاوية أو اختر اتجاهًا",
|
||||
"ui.construction.bisector_hint": "منصف زاوية: اختر خطين مستقيمين متقاطعين ثم الحل المطلوب",
|
||||
"ui.construction.common_hint": "مماس مشترك: اختر دائرتين/قوسين ثم الحل المطلوب",
|
||||
"ui.construction.contact_hint": "مماس: اختر دائرة/قوسًا أو منحنى شريحيًا/قطعًا مخروطيًا مفتوحًا ثم نقطة التماس (للمنحنيات الحرة: النهايات فقط)",
|
||||
"ui.construction.external_hint": "مماس: اختر دائرة أو قوسًا ثم نقطة خارجية ثم الحل المطلوب",
|
||||
"ui.construction.free_hint": "خط إنشائي: انقر نقطتين؛ انقر بزر الفأرة الأيمن للبدء من جديد",
|
||||
"ui.construction.point_hint": "خط إنشائي: انقر نقطة المرور",
|
||||
"ui.construction.reference_hint": "خط إنشائي: اختر خطًا مستقيمًا ثم نقطة؛ انقر بزر الفأرة الأيمن لتغيير المرجع",
|
||||
"ui.construction.ribbon_label": "خطوط مساعدة",
|
||||
"ui.context_menu": "القائمة السياقية",
|
||||
"ui.continuity_g0": "G0 تجعّد",
|
||||
"ui.continuity_g1": "G1 مماس",
|
||||
@@ -3998,6 +4428,7 @@
|
||||
"ui.dark": "داكن",
|
||||
"ui.default_modelling_orientation": "اتجاه النمذجة الافتراضي",
|
||||
"ui.delete": "حذف",
|
||||
"ui.delete_select_first": "حدّد أولًا ما تريد حذفه: الميزات أو الأجسام أو المكونات أو هندسة الرسم",
|
||||
"ui.depth": "العمق",
|
||||
"ui.design": "التصميم",
|
||||
"ui.design_properties.author": "المؤلف",
|
||||
@@ -4012,6 +4443,40 @@
|
||||
"ui.design_properties.project": "المشروع",
|
||||
"ui.design_properties.revision": "المراجعة",
|
||||
"ui.design_saved": "تم الحفظ في {path}",
|
||||
"ui.details_access_caption": "توضح الأوجه ما إذا كان بإمكان الأداة الوصول إليها من الاتجاه المحدد.",
|
||||
"ui.details_angle": "الزاوية",
|
||||
"ui.details_continuity_caption": "حرّر الوصلة المحددة. تحتفظ الوصلات الأخرى بإعداداتها الخاصة.",
|
||||
"ui.details_continuity_stale": "هندسة سابقة: أعد تشغيل التحليل لتحرير هذه الوصلة أو ملاءمة العرض لها.",
|
||||
"ui.details_copy_list": "نسخ القائمة",
|
||||
"ui.details_curvature": "تفاوت الانحناء",
|
||||
"ui.details_curvature_caption": "تُلوَّن الأوجه وفقًا لنصف قطر الانحناء المحلي لها.",
|
||||
"ui.details_direction": "اتجاه الأداة",
|
||||
"ui.details_draft_caption": "تُلوَّن الأوجه وفقًا لزاويتها بالنسبة إلى اتجاه السحب.",
|
||||
"ui.details_edit_seam": "تحرير الوصلة",
|
||||
"ui.details_fixture": "نموذج عرض لمكوّن الواجهة — بيانات توضيحية فقط",
|
||||
"ui.details_fixture_caption": "نموذج عرض لمكوّن الواجهة بقيم توضيحية؛ هذه ليست نتيجة من النموذج الهندسي.",
|
||||
"ui.details_fixture_problem": "مثال على نتيجة تشير إلى مشكلة",
|
||||
"ui.details_fixture_readout": "مثال على قيمة مقاسة",
|
||||
"ui.details_flip": "قلب",
|
||||
"ui.details_gap": "الفجوة",
|
||||
"ui.details_hatch": "تهشير أوجه القطع",
|
||||
"ui.details_jump": "قفزة الانحناء",
|
||||
"ui.details_key": "مفتاح الألوان",
|
||||
"ui.details_offset": "إزاحة",
|
||||
"ui.details_plane": "مستوى",
|
||||
"ui.details_pull": "اتجاه السحب",
|
||||
"ui.details_radius": "نصف القطر",
|
||||
"ui.details_readout": "القراءات",
|
||||
"ui.details_samples": "العينات",
|
||||
"ui.details_seam": "{body} · حافة {edge}",
|
||||
"ui.details_settings": "الإعدادات",
|
||||
"ui.details_sharp_gap": "حافة حادة أو فجوة",
|
||||
"ui.details_show_all": "عرض الكل ({count})",
|
||||
"ui.details_smooth": "أملس",
|
||||
"ui.details_stripes": "الخطوط",
|
||||
"ui.details_target": "ملاءمة العرض للهندسة",
|
||||
"ui.details_worst_seams": "الوصلات الأقل استمرارية",
|
||||
"ui.details_zebra_caption": "تُظهر الخطوط المنعكسة مدى سلاسة اتصال الأوجه.",
|
||||
"ui.diameter": "القطر",
|
||||
"ui.dimension": "البُعد",
|
||||
"ui.direct_interaction": "التفاعل المباشر",
|
||||
@@ -4056,6 +4521,7 @@
|
||||
"ui.edit_in_place_saved_elsewhere": "حُفظ الجزء في ملف آخر؛ ما زال التجميع مرتبطًا بـ {name}",
|
||||
"ui.edit_in_place_wait": "انتظر حتى ينتهي ما يجري في التصميم",
|
||||
"ui.edit_section_analysis": "تعديل تحليل المقطع",
|
||||
"ui.edit_sketch_empty": "لا توجد رسومات لتعديلها",
|
||||
"ui.ellipse": "قطع ناقص",
|
||||
"ui.emboss_wrap_note": "تلتف ملامح الخطوط المتعامدة المماسة لأسطوانة مدعومة تلقائيًا. اختر جدارًا لتحديد الهدف.",
|
||||
"ui.end_radius": "نصف قطر النهاية",
|
||||
@@ -4066,12 +4532,15 @@
|
||||
"ui.equation_explicit": "صريح",
|
||||
"ui.equation_form": "الشكل",
|
||||
"ui.equation_note": "المتغير رقم بلا وحدة: تأخذه sin(t) بالراديان. والنتيجة التي بلا وحدة تكون بوحدة التصميم.",
|
||||
"ui.equation_note_range": "المتغير طول مثل نطاقه: يمكن دمجه مع معاملات الطول، واقسمه على طول قبل تمريره إلى sin(). والنتيجة التي بلا وحدة تكون بوحدة التصميم.",
|
||||
"ui.equation_parametric": "بارامتري",
|
||||
"ui.equation_variable_unit": "المتغير يأخذ وحدة النطاق",
|
||||
"ui.equation_x_of_t": "x(t)",
|
||||
"ui.equation_y_of_t": "y(t)",
|
||||
"ui.equation_y_of_x": "y(x)",
|
||||
"ui.equivalent_radius": "نصف القطر المكافئ",
|
||||
"ui.expand": "توسيع",
|
||||
"ui.explode_needs_two_components": "يُبعد العرض المفكك المكوّنات بعضها عن بعض، لذا يحتاج التصميم إلى مكوّنين أو أكثر (مكوّن جديد، أو إدراج تصميم، أو إنشاء مكوّنات من الأجسام)",
|
||||
"ui.exportDxf": "تصدير DXF…",
|
||||
"ui.export_ellipsis_keymap": "تصدير…",
|
||||
"ui.export_keymap_tip": "المفاتيح ومفضلات مربع S وشريط الأدوات، كملف",
|
||||
@@ -4240,12 +4709,14 @@
|
||||
"ui.joints": "المفاصل",
|
||||
"ui.keyboard_shortcuts": "الاختصارات",
|
||||
"ui.language": "اللغة",
|
||||
"ui.lasso_select": "التحديد الحر (ارسم حلقة حرة بالسحب: يحدّد ما يقع داخلها بالكامل)",
|
||||
"ui.layout_compact": "مضغوط",
|
||||
"ui.layout_floating": "عائم",
|
||||
"ui.length": "الطول",
|
||||
"ui.length_decimals": "المنازل العشرية للأطوال",
|
||||
"ui.light": "فاتح",
|
||||
"ui.line": "خط",
|
||||
"ui.line_arc_hint": "قوس مماسي: انقر نهاية القوس. توقف عند آخر نقطة مرة أخرى للعودة إلى الخطوط؛ انقر بالزر الأيمن أو اضغط Esc للإنهاء",
|
||||
"ui.link_copies": "ربط النسخ المتطابقة",
|
||||
"ui.link_copies_keep": "إبقاء",
|
||||
"ui.link_copies_link": "ربط",
|
||||
@@ -4334,6 +4805,7 @@
|
||||
"ui.part_size_shared": "يعيد بناء القطعة مستبدلًا أي ميزات مضافة. تتحدث كل نسخ هذا المكوّن.",
|
||||
"ui.paste": "لصق",
|
||||
"ui.path": "المسار",
|
||||
"ui.pattern_object_type_tip": "الأجسام: أشكال مصمتة تُختار في العرض أو في المستعرض؛ يُنسخ كل منها كاملًا.\nالميزات: خطوات في السجل، مثل بثق أو ثقب، تُختار في السجل أو على وجه صنعته؛ تتكرر الخطوة.\nالرسم ليس أيًّا منهما: كرّر منحنياته بأداة النمط أو المرآة داخل الرسم، أو ابثقه أولًا.",
|
||||
"ui.pattern_on_path": "نمط على مسار",
|
||||
"ui.perforate_margin_default": "من القطر",
|
||||
"ui.perforate_pitch": "الخطوة",
|
||||
@@ -4360,12 +4832,17 @@
|
||||
"ui.plugins_skipped": "تعذّرت قراءة {count} مجلد(ات).",
|
||||
"ui.plugins_version": "{version}",
|
||||
"ui.point": "نقطة",
|
||||
"ui.point_cloud_add_filter": "إضافة مرشح…",
|
||||
"ui.point_cloud_auto_range": "نطاق تلقائي",
|
||||
"ui.point_cloud_color_by": "التلوين حسب",
|
||||
"ui.point_cloud_file_colors": "ألوان الملف",
|
||||
"ui.point_cloud_filter_by": "التصفية حسب",
|
||||
"ui.point_cloud_height_high": "أعلى ارتفاع",
|
||||
"ui.point_cloud_height_low": "أدنى ارتفاع",
|
||||
"ui.point_cloud_legend_filter": "تُعرض وتُخفى في وسيلة الإيضاح أعلاه",
|
||||
"ui.point_cloud_no_file_colors": "لا يحتوي الملف على ألوان",
|
||||
"ui.point_cloud_pause": "إيقاف مؤقت",
|
||||
"ui.point_cloud_play": "تشغيل",
|
||||
"ui.point_cloud_single_color": "لون واحد",
|
||||
"ui.point_cloud_size": "حجم النقطة",
|
||||
"ui.point_cloud_units": "وحدات الملف",
|
||||
@@ -4374,6 +4851,11 @@
|
||||
"ui.polygon": "مضلع",
|
||||
"ui.preferences": "التفضيلات",
|
||||
"ui.press_a_key": "اضغط مفتاحًا…",
|
||||
"ui.print_face_cleared": "{body}: تم مسح وجه الطباعة",
|
||||
"ui.print_face_input": "وجه الطباعة",
|
||||
"ui.print_face_one_body": "يُختار وجه الطباعة لجسم واحد: أرسل ذلك الجسم وحده لتغييره",
|
||||
"ui.print_face_pick": "اختر وجهًا مستويًا واحدًا لجسم صلب لجعله وجه الطباعة",
|
||||
"ui.print_face_set": "{body}: تم تعيين وجه الطباعة؛ الإرسال إلى برنامج التقطيع يضع الجسم عليه",
|
||||
"ui.profile": "المقطع",
|
||||
"ui.profile_plane": "مستوى المقطع",
|
||||
"ui.profiles": "المقاطع",
|
||||
@@ -4389,6 +4871,7 @@
|
||||
"ui.properties.inertia_y": "Iyx, Iyy, Iyz",
|
||||
"ui.properties.inertia_z": "Izx, Izy, Izz",
|
||||
"ui.properties.measuring": "جارٍ القياس…",
|
||||
"ui.properties.measuring_bodies": "جارٍ قياس الأجسام… {done} من {total}",
|
||||
"ui.properties.measuring_failed": "توقف القياس قبل أن يكتمل.",
|
||||
"ui.properties.principal_axis": "المحور الرئيسي {number}",
|
||||
"ui.properties.principal_moments": "العزوم الرئيسية",
|
||||
@@ -4437,6 +4920,7 @@
|
||||
"ui.revolve": "دوران",
|
||||
"ui.ribbon_exit": "خروج",
|
||||
"ui.ribbon_labels": "إظهار النص تحت أيقونات الشريط",
|
||||
"ui.ribbon_menus_skip_pinned": "استبعاد الأوامر المثبتة من القوائم المنسدلة",
|
||||
"ui.ribbon_pin_footer": "الأوامر المثبتة تظهر في الشريط. مرّر المؤشر على صف لتثبيته أو إلغاء تثبيته.",
|
||||
"ui.ribbon_workspace": "مساحة العمل",
|
||||
"ui.right": "يمين",
|
||||
@@ -4455,6 +4939,7 @@
|
||||
"ui.selectOther": "تحديد آخر…",
|
||||
"ui.selectTangentChain": "تحديد سلسلة مماسية",
|
||||
"ui.select_all": "تحديد الكل",
|
||||
"ui.select_components_by_face": "تحديد المكوّنات (تحديد وجه يحدّد المكوّن الذي ينتمي إليه)",
|
||||
"ui.selection": "التحديد",
|
||||
"ui.selection_modifiers": "مُعدِّلات التحديد",
|
||||
"ui.selection_shift_add_only": "Shift مع النقر يضيف دون إزالة",
|
||||
@@ -4496,6 +4981,11 @@
|
||||
"ui.sketch_intersect_selection_filter": "مرشح التحديد",
|
||||
"ui.sketch_modifiers": "مُعدِّلات الرسم",
|
||||
"ui.sketch_project_geometry": "الهندسة",
|
||||
"ui.sketch_report.all_constrained": "كل شيء مقيد بالكامل.",
|
||||
"ui.sketch_report.dof": "درجات الحرية",
|
||||
"ui.sketch_report.loose": "غير مقيد بالكامل",
|
||||
"ui.sketch_report.status": "الحالة",
|
||||
"ui.sketch_report.title": "تقرير الرسم",
|
||||
"ui.sketch_scale": "تحجيم الرسم",
|
||||
"ui.sketches": "الرسومات",
|
||||
"ui.slice": "تقطيع",
|
||||
@@ -4600,10 +5090,19 @@
|
||||
"ui.view_centre": "مركز العرض",
|
||||
"ui.viewport_status_clear": "إيقاف {name}",
|
||||
"ui.viewport_status_clear_hint": "إيقاف {name} · Esc",
|
||||
"ui.viewport_status_edges": "{count} حواف",
|
||||
"ui.viewport_status_from": "من {direction}",
|
||||
"ui.viewport_status_key": "إظهار مفتاح الألوان لـ {name}",
|
||||
"ui.viewport_status_minimum_radius": "أقل نصف قطر",
|
||||
"ui.viewport_status_pairs": "{count} أزواج",
|
||||
"ui.viewport_status_section_hatch": "{setting} · تهشير",
|
||||
"ui.viewport_status_section_plane": "المستوى الحالي",
|
||||
"ui.viewport_status_section_tilted": "مائل · {offset}",
|
||||
"ui.viewport_status_stripes": "{count} شريطًا",
|
||||
"ui.viewport_status_summary_clear": "إيقاف كل شيء",
|
||||
"ui.viewport_status_summary_heading": "في هذا العرض",
|
||||
"ui.viewport_status_summary_label": "{name} و{count} عناصر أخرى",
|
||||
"ui.viewport_status_summary_more": "+{count}",
|
||||
"ui.viewport_theme_follow": "اتباع السمة",
|
||||
"ui.visual_shaded_hidden_edges": "مظلل مع الحواف المخفية",
|
||||
"ui.visual_shaded_with_edges": "مظلل مع الحواف",
|
||||
@@ -4640,7 +5139,9 @@
|
||||
"update.button": "تحديث",
|
||||
"update.button_version": "التحديث إلى {version}",
|
||||
"update.check_automatically": "التحقق من التحديثات تلقائيًا",
|
||||
"update.check_for_updates": "التحقق من وجود تحديثات",
|
||||
"update.check_now": "تحقق الآن",
|
||||
"update.check_unavailable": "التحقق من التحديثات غير متاح لهذا التثبيت.",
|
||||
"update.checking": "جارٍ التحقق…",
|
||||
"update.copy": "نسخ",
|
||||
"update.dmg_opened": "صورة القرص مفتوحة وموثّقة: اسحب SolidCraft إلى مجلد التطبيقات مستبدلًا النسخة القديمة، ثم أعد تشغيل SolidCraft.",
|
||||
|
||||
@@ -1,22 +1,42 @@
|
||||
{
|
||||
"A Single hole snaps to the middle of its face and to the centres of its round edges": "A Single hole snaps to the middle of its face and to the centres of its round edges",
|
||||
"Base Center": "Base Centre",
|
||||
"Center X": "Centre X",
|
||||
"Center Y": "Centre Y",
|
||||
"Center of mass": "Centre of mass",
|
||||
"Centre to centre": "Centre to centre",
|
||||
"Circle center": "Circle centre",
|
||||
"Colour": "Colour",
|
||||
"Copy all licences": "Copy all licences",
|
||||
"Customize Toolbar": "Customise Toolbar",
|
||||
"Customize…": "Customise…",
|
||||
"Face center": "Face centre",
|
||||
"Favorites": "Favourites",
|
||||
"Favourite": "Favourite",
|
||||
"Mass Center": "Mass Centre",
|
||||
"Modeled": "Modelled",
|
||||
"Select the centre the pattern turns around first": "Select the centre the pattern turns around first",
|
||||
"Snap to face and edge centres": "Snap to face and edge centres",
|
||||
"Specialise": "Specialise",
|
||||
"cmd.appearance_favorite": "Favourite Look",
|
||||
"cmd.component_cycle_color": "Cycle Component Colour",
|
||||
"cmd.construct_point_center": "Point At Centre Of Circle/Sphere/Torus",
|
||||
"cmd.inspect_center_of_mass": "Centre of Mass",
|
||||
"cmd.inspect_colored_components": "Enable Component Colours",
|
||||
"cmd.inspect_colored_components_disable": "Disable Component Colours",
|
||||
"cmd.parameters_favorite": "Favourite Parameter",
|
||||
"cmd.render_aging_describe": "Layered Surface Aging",
|
||||
"cmd.render_effects_describe": "Lens and Creative Effects",
|
||||
"cmd.sketch.construction_line": "Construction Line",
|
||||
"cmd.sketch.construction_line.angle": "Construction Line at Angle",
|
||||
"cmd.sketch.construction_line.bisector": "Angle Bisector",
|
||||
"cmd.sketch.construction_line.horizontal": "Horizontal Construction Line",
|
||||
"cmd.sketch.construction_line.parallel": "Parallel Construction Line",
|
||||
"cmd.sketch.construction_line.perpendicular": "Perpendicular Construction Line",
|
||||
"cmd.sketch.construction_line.tangent_at": "Tangent at Curve Point",
|
||||
"cmd.sketch.construction_line.tangent_external": "Tangent through External Point",
|
||||
"cmd.sketch.construction_line.tangent_two": "Common Tangent",
|
||||
"cmd.sketch.construction_line.vertical": "Vertical Construction Line",
|
||||
"cmd.sketch_arc_center_point": "Centre Point Arc",
|
||||
"cmd.sketch_circle_center": "Centre Diameter Circle",
|
||||
"cmd.sketch_rectangle_center": "Centre Rectangle",
|
||||
@@ -27,8 +47,33 @@
|
||||
"color.edit": "Click to edit colour",
|
||||
"color.gamma": "Showing colour values in 0-255 gamma space",
|
||||
"color.linear": "Showing colour values in 0-1 linear space",
|
||||
"color.recent": "Recent colours",
|
||||
"color.recent_help": "Colours you pick in any colour field appear here",
|
||||
"color.saturation": "Saturation (per cent)",
|
||||
"color.selected": "Selected colour",
|
||||
"color.step_down": "Step down",
|
||||
"color.step_up": "Step up",
|
||||
"color.value": "Value, the brightness (per cent)",
|
||||
"dxf.cancelled": "DXF export cancelled",
|
||||
"dxf.cancelling": "Cancelling DXF export",
|
||||
"help.apache": "Apache licence 2.0",
|
||||
"help.appearance.assign": "Gives the selected bodies, faces or components a colour or a material look, without changing their weight. Use it to tell parts apart or to preview a finish.",
|
||||
"help.face.delete": "Removes the selected faces and lets the neighbouring faces close the gap, or leaves the gap open as a surface. Use it to take off a rounded edge, a hole or a boss that is in the way.",
|
||||
"help.font_details": "The interface uses egui's built-in fonts (Ubuntu Light and Hack, under the Ubuntu Font Licence and the MIT/Bitstream Vera licence; Noto Emoji and the emoji icon font, under the OFL and MIT). Sketch text uses Liberation Sans (SIL OFL 1.1). The Crafting Apps' optional font pack, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1), is not bundled in SolidCraft builds.",
|
||||
"help.licences": "Licences",
|
||||
"help.material.assign": "Sets what the selected bodies are made of, such as steel, aluminium or ABS. Use it so that the mass and weight match the real part.",
|
||||
"help.mit": "MIT licence",
|
||||
"help.solid.draft": "Tilts the selected faces by the angle you set, measured from a neutral plane. Use it on moulded or cast parts so that they slide out of the mould.",
|
||||
"help.solid.revolve": "Spins a sketch profile around an axis to make a round solid. Use it for shafts, knobs, bowls and any part that is round about a centre line.",
|
||||
"help.solid.split_body": "Cuts a body into separate bodies with a plane, the face of another body or a sketch line. Use it to make parts that are printed, machined or coloured on their own.",
|
||||
"help.solid.split_face": "Divides the selected faces along a plane, the face of another body or sketch curves, without cutting the body. Use it to give part of a face its own draft, colour or offset.",
|
||||
"help.third_party": "Third-party licences",
|
||||
"home.new_mm_hint": "Millimetres · opens in Design",
|
||||
"navbar.custom.customise": "Customise navigation bar…",
|
||||
"navbar.custom.position_centre": "Centre",
|
||||
"navbar.description.separator": "A thin line that groups neighbouring slots.",
|
||||
"pattern.alignment_hint": "Counts include the original. Centre balances copies; Flip chooses the extra side for even totals.",
|
||||
"prefs.bottom_centre": "Bottom centre",
|
||||
"prefs.logo_theme": "Theme's colours",
|
||||
"prefs.max_file_size": "Largest file to open",
|
||||
"prefs.max_file_size_design": "Design files",
|
||||
@@ -39,17 +84,27 @@
|
||||
"prefs.megabytes": "MB",
|
||||
"prefs.sketch_conflict_colour": "Conflicting geometry in the conflict colour",
|
||||
"prefs.sketch_conflict_colour_note": "While a sketch's constraints conflict, the curves and points a failing constraint holds are drawn in the conflict colour too, not only its glyph or dimension. Off: they keep their usual colours.",
|
||||
"prefs.sketch_construction_lines": "Extended construction line tools",
|
||||
"prefs.sketch_recent_snap": "Auto snap to recent centres and midpoints",
|
||||
"prefs.sketch_recent_snap_note": "While drawing, snap the cursor where the guides of the two most recent circle centres or straight-edge midpoints cross. Off: those guides stay visual and the cursor does not move.",
|
||||
"prefs.sketch_state_icons": "Sketch icons in the colour of their state",
|
||||
"prefs.sketch_state_icons_note": "In History and the browser, a sketch's icon takes the colour of its state (under constrained, fully constrained or conflicting) and its tooltip names the state. Off: every sketch has the same icon.",
|
||||
"prefs.sketch_tracking_guides": "Centre and midpoint alignment guides",
|
||||
"prefs.sketch_tracking_guides_note": "Hover over a circle centre or straight-edge midpoint, then move horizontally or vertically to show a temporary dotted guide.",
|
||||
"prefs.status_bar_note": "A thin bar along the window's bottom edge shows what is being edited, the open sketch's state in its colour and the design's units; a click on the units changes them. The sketch's state then no longer shows in the view's corner.",
|
||||
"prefs.structure.appearance_note": "Colours, text and accessibility.",
|
||||
"prefs.structure.tools_note": "How modelling tools behave.",
|
||||
"prefs.theme_follow": "Follow a theme file",
|
||||
"prefs.theme_follow_error": "Not applied: {error}. The last good theme stays on.",
|
||||
"prefs.theme_follow_launch": "Followed for this run only (--theme-file); reloaded whenever another tool rewrites it.",
|
||||
"prefs.theme_follow_note": "Reloaded whenever another tool rewrites it. Choosing a theme stops following it.",
|
||||
"prefs.theme_follow_off": "Off",
|
||||
"prefs.theme_follow_stop": "Stop following",
|
||||
"prefs.theme_option_opacity_help": "Adjust floating panel opacity. A readability floor protects text over viewport colours.",
|
||||
"prefs.theme_option_tab_colours": "Tab colours",
|
||||
"prefs.theme_option_tab_colours_help": "Use this theme’s panel and viewport colours for each ribbon tab.",
|
||||
"prefs.theme_option_tab_fade_ms_help": "Fade panel and viewport colours when switching tabs. Zero switches instantly.",
|
||||
"prefs.trackpad_zoom_modifier.help": "Hold only this key to zoom at the pointer with vertical scroll. Off keeps the existing scroll behaviour.",
|
||||
"prefs.view": "View behaviour",
|
||||
"prefs.viewport_background_colour": "Colour",
|
||||
"render.aging_add": "Add aging layer",
|
||||
@@ -79,6 +134,7 @@
|
||||
"render.aging_target_help": "A named target must still match its captured index and name. Global masks are world-anchored; they do not follow moving parts. This is neither cavity detection nor true edge wear. Filter the list to reach additional bodies.",
|
||||
"render.aging_target_search": "Filter body names",
|
||||
"render.aging_upward": "Upward-facing deposition",
|
||||
"render.appearance_editor.base_colour": "Base colour",
|
||||
"render.backdrop_first": "Start / centre colour",
|
||||
"render.backdrop_second": "End / edge colour",
|
||||
"render.backdrop_x": "Centre X",
|
||||
@@ -95,21 +151,31 @@
|
||||
"render.base_color": "Base colour · sRGB",
|
||||
"render.bloom_help": "Creative output-only glow from positive linear highlights, spread with three normalised box passes. Radius is in output pixels. Added in linear display light before sRGB; not a lens, volumetric effect or convergence improvement. The raw EXR is unchanged.",
|
||||
"render.chromatic_offset": "Chromatic edge offset",
|
||||
"render.cpu_area_editor_help": "Full side vectors in millimeters; U cross V points towards the emitting side. This differs from GPU half-edge vectors.",
|
||||
"render.cpu_light_help": "Up to eight directional lights. An empty custom list turns them off; selecting a preset restores its lights. Colours are linear RGB and intensity is relative, not watts.",
|
||||
"render.cpu_linear_color": "Linear colour (R, G, B)",
|
||||
"render.effects_gpu_only": "These effects require GPU path tracing. Changing the page never switches the renderer automatically.",
|
||||
"render.effects_help": "Combine ordered colour looks and image-space lens effects. Rendering and raw-master regrading use the same saved settings. Raw EXR stays unchanged. These are original artistic controls, not calibrated lens or branded-film emulations.",
|
||||
"render.effects_reset_lens": "Reset lens effects",
|
||||
"render.effects_seed": "Pattern seed",
|
||||
"render.env_colour": "Colour",
|
||||
"render.environment.radial_only": "Centre and radius apply to Radial mode.",
|
||||
"render.error_finish_gesture": "finish the modelling gesture before previewing",
|
||||
"render.error_finish_operation": "finish the current modelling operation before entering Render",
|
||||
"render.film_grain": "Photographic grain",
|
||||
"render.flare_ghosts": "Ghost rings per source",
|
||||
"render.flare_halo": "Flare halo",
|
||||
"render.flare_streak": "Anamorphic-style streak",
|
||||
"render.flare_strength": "Highlight flare strength",
|
||||
"render.flare_threshold": "Scene-linear flare threshold",
|
||||
"render.frame_centre_mark": "Centre mark",
|
||||
"render.hdr_primaries_declared": "The source declares its colour primaries.",
|
||||
"render.hdr_primaries_srgb": "Colour primaries: sRGB/D65",
|
||||
"render.hdr_primaries_undeclared": "The source does not declare primaries; review the renderer colour requirements.",
|
||||
"render.image_cancelled": "Render cancelled",
|
||||
"render.image_cancelling": "Cancelling",
|
||||
"render.image_scene_stale": "Finish the modelling gesture or refresh the scene before checking or starting an image.",
|
||||
"render.inspector_colour": "Colour",
|
||||
"render.layer_down": "Move down",
|
||||
"render.layer_enabled": "Layer enabled",
|
||||
"render.layer_remove": "Remove layer",
|
||||
@@ -124,6 +190,11 @@
|
||||
"render.library_rig_help": "Fit once at an explicit centre and physical extent. Complete rigs include passive cards; calibration blockers still refuse. Conservative emitter/card clearance is checked before saving.",
|
||||
"render.library_source_preview_help": "Authored base-colour source map. This is not a rendered or measured material preview.",
|
||||
"render.library_unfavorite": "Remove favourite",
|
||||
"render.light_behaviour": "BEHAVIOUR",
|
||||
"render.light_preview_help": "Live view is unshadowed; Area lights use a centre-sample approximation. Render uses the complete light model.",
|
||||
"render.light_product_centre": "Product centre",
|
||||
"render.light_temperature": "Colour temperature",
|
||||
"render.lighting_colour": "Colour",
|
||||
"render.look_add": "Add colour look",
|
||||
"render.look_bleach": "Bleach-bypass-inspired",
|
||||
"render.look_cool": "Cool",
|
||||
@@ -147,30 +218,47 @@
|
||||
"render.radial_distortion": "Radial distortion",
|
||||
"render.ribbon_aging": "Aging",
|
||||
"render.ribbon_effects": "Effects",
|
||||
"render.ribbon_studios_help": "Browse implemented studio compositions and review their replacements before applying. Concept-only scenes remain labelled.",
|
||||
"render.sharpening": "Detail sharpening",
|
||||
"render.soft_focus": "Soft focus",
|
||||
"render.stage_panels.centre": "Centre",
|
||||
"render.stage_panels.source_note": "Authored base-colour source map. Not a measured material.",
|
||||
"render.studio_area_help": "Up to four one-sided rectangles. Orthogonal half-edges U and V define size; U × V faces the lit side. Coordinates are world-space millimetres.",
|
||||
"render.studio_center": "Centre X, Y, Z (mm)",
|
||||
"render.studio_hdr_help": "Radiance .hdr, 2:1 panorama, up to 2048 × 1024. EXR is unavailable. The colour assumption applies only when primaries are unspecified.",
|
||||
"sketch_text.align_center": "Centre",
|
||||
"ui.3d_mouse_kind_cap": "Return to Centre",
|
||||
"ui.3d_mouse_looks_like_cap": "The reading stays put while you hold it, the way a Return to Centre device does.",
|
||||
"ui.3d_mouse_orbit_tip": "Traced: the 3D mouse turns the view around the part of the model in the middle of the view when the turn begins, marked by a faint ball. Classic: around the view's centre",
|
||||
"ui.3d_mouse_step_pull": "Pull the cap towards you, hold it, then let go.",
|
||||
"ui.3d_mouse_switch_cap": "Calibrate as Return to Centre",
|
||||
"ui.agent_chat_minimize": "Minimise to a strip",
|
||||
"ui.ai_mode_edits_note": "Modelling commands run without asking; saving, opening, exporting and other file or destructive actions still ask.",
|
||||
"ui.center": "Centre",
|
||||
"ui.center_arc_follows_cursor": "Centre point arc follows the cursor's direction",
|
||||
"ui.center_arc_follows_cursor_tip": "A centre point arc runs clockwise or counter-clockwise the way the cursor goes round its centre. Off: always counter-clockwise from the start.",
|
||||
"ui.centerline": "Centreline",
|
||||
"ui.colour_vision": "Colour vision",
|
||||
"ui.colour_vision_note": "Changes the colours that carry a meaning: sketch states, axes, bends, analyses and icons. If you use Windows colour filters, keep this Off.",
|
||||
"ui.colour_vision_off_tip": "The theme's own colours",
|
||||
"ui.construction.ribbon_label": "X-Lines",
|
||||
"ui.customizeToolbar": "Customise Toolbar…",
|
||||
"ui.default_modelling_orientation": "Default modelling orientation",
|
||||
"ui.design_properties.license": "Licence",
|
||||
"ui.design_properties.organization": "Organisation",
|
||||
"ui.details_curvature_caption": "Faces are coloured by their local radius of curvature.",
|
||||
"ui.details_draft_caption": "Faces are coloured by their angle to the pull direction.",
|
||||
"ui.export_keymap_tip": "Keys, S box favourites and the toolbar, as a file",
|
||||
"ui.layout_compact": "Compact",
|
||||
"ui.layout_floating": "Floating",
|
||||
"ui.material_review.claims": "Sources and licences are unverified claims. Missing values remain unknown.",
|
||||
"ui.point_cloud_color_by": "Colour By",
|
||||
"ui.point_cloud_file_colors": "File Colours",
|
||||
"ui.point_cloud_no_file_colors": "The file has no colours",
|
||||
"ui.point_cloud_single_color": "Single Colour",
|
||||
"ui.properties.inertia_note": "About the centre of mass, in world axes (g·{unit}²)",
|
||||
"ui.ribbon_labels": "Show text under ribbon icons",
|
||||
"ui.view_centre": "View centre",
|
||||
"ui.workspace_layout": "Workspace layout",
|
||||
"ui.zoom_to_cursor_tip": "The wheel zooms towards the point under the cursor (off: towards the view's centre)",
|
||||
"update.prefs_flatpak": "Flatpak updates this copy ({version}): run {command} or use your software centre. SolidCraft doesn't check."
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
"BLEND SURFACE": "משטח מעבר",
|
||||
"BOUNDARY SURFACE": "משטח גבול",
|
||||
"BROWSER": "עץ התכן",
|
||||
"Back to the original order": "חזרה לסדר המקורי",
|
||||
"Ball": "כדורי",
|
||||
"Bar": "מוט",
|
||||
"Base Center": "מרכז הבסיס",
|
||||
@@ -595,6 +596,8 @@
|
||||
"Snap to face and edge centres": "הצמדה למרכזי פאות ומקצועות",
|
||||
"SolidCraft cannot submit reports directly. Submit on GitHub; no token is needed in the app.": "אין אפשרות לשלוח דיווחים ישירות מתוך SolidCraft. יש לשלוח אותם ב-GitHub; אין צורך באסימון גישה באפליקציה.",
|
||||
"SolidCraft closed before these designs were saved. Their last autosave can be opened.": "SolidCraft נסגרה לפני שתכנים אלה נשמרו. אפשר לפתוח את השמירה האוטומטית האחרונה שלהם.",
|
||||
"Sort A to Z": "מיון בסדר עולה",
|
||||
"Sort Z to A": "מיון בסדר יורד",
|
||||
"Spacing 2 must be a non-zero number": "מרווח 2 חייב להיות מספר שונה מאפס",
|
||||
"Spacing must be a non-zero number": "המרווח חייב להיות מספר שונה מאפס",
|
||||
"Specialise": "התמחות",
|
||||
@@ -775,6 +778,8 @@
|
||||
"at the face": "על הפאה",
|
||||
"bom.group_children": "תת-חלקים בשורת החלק שלהם",
|
||||
"browser.body_name": "גוף{number}",
|
||||
"browser.calibrate_click_a": "לחצו על התמונה כדי לבחור את נקודה A, או הקלידו את הקואורדינטות שלה.",
|
||||
"browser.calibrate_click_b": "לחצו על התמונה כדי לבחור את נקודה B, או הקלידו את הקואורדינטות שלה.",
|
||||
"browser.calibrate_title": "כיול: {name}",
|
||||
"browser.capture_many": "{count} רכיבים הוזזו, אך המיקומים שלהם לא נלכדו.",
|
||||
"browser.capture_note": "לכידה שומרת את המיקום החדש; החזרה מחזירה את המיקום הקודם.",
|
||||
@@ -817,6 +822,8 @@
|
||||
"cmd.appearance_pick_up": "בחירת מראה",
|
||||
"cmd.appearance_replace": "החלפת מראה",
|
||||
"cmd.assembly_bom": "רשימת חלקים",
|
||||
"cmd.assembly_mass_properties": "תכונות מסה",
|
||||
"cmd.body.print_face": "פאת הדפסה",
|
||||
"cmd.body_rename": "שינוי שם גוף",
|
||||
"cmd.browser_collapse_all": "כיווץ הכול",
|
||||
"cmd.browser_expand_all": "הרחבת הכול",
|
||||
@@ -1101,6 +1108,16 @@
|
||||
"cmd.sheet_refold": "קיפול מחדש",
|
||||
"cmd.sheet_rules": "רשימת כללי פח",
|
||||
"cmd.sheet_unfold": "פתיחת קיפול",
|
||||
"cmd.sketch.construction_line": "ישר עזר",
|
||||
"cmd.sketch.construction_line.angle": "ישר עזר בזווית",
|
||||
"cmd.sketch.construction_line.bisector": "חוצה זווית",
|
||||
"cmd.sketch.construction_line.horizontal": "ישר עזר אופקי",
|
||||
"cmd.sketch.construction_line.parallel": "ישר עזר מקביל",
|
||||
"cmd.sketch.construction_line.perpendicular": "ישר עזר ניצב",
|
||||
"cmd.sketch.construction_line.tangent_at": "משיק בנקודה על העקומה",
|
||||
"cmd.sketch.construction_line.tangent_external": "משיק דרך נקודה חיצונית",
|
||||
"cmd.sketch.construction_line.tangent_two": "משיק משותף",
|
||||
"cmd.sketch.construction_line.vertical": "ישר עזר אנכי",
|
||||
"cmd.sketch_arc3d": "קשת תלת־ממדית",
|
||||
"cmd.sketch_arc_center_point": "קשת מרכז ונקודה",
|
||||
"cmd.sketch_arc_tangent": "קשת משיקה",
|
||||
@@ -1231,6 +1248,7 @@
|
||||
"cmd.view.render_browser": "דפדפן רינדור",
|
||||
"cmd.view.render_dock": "הזז את עגינת הרינדור",
|
||||
"cmd.view.render_focus": "תצוגת מיקוד רינדור",
|
||||
"cmd.view.status_details": "פרטי מצב חלון התצוגה",
|
||||
"cmd.view.status_items": "פריטי מצב תצוגה",
|
||||
"cmd.view_ambient_occlusion": "הצללה סביבתית",
|
||||
"cmd.view_angle_readout": "זוויות תצוגה",
|
||||
@@ -1269,8 +1287,14 @@
|
||||
"color.hex_hint": "#rrggbb",
|
||||
"color.hue": "גוון",
|
||||
"color.linear": "ערכי הצבע מוצגים במרחב לינארי 0-1",
|
||||
"color.recent": "צבעים אחרונים",
|
||||
"color.recent_help": "צבעים שבוחרים בכל שדה צבע מופיעים כאן",
|
||||
"color.saturation": "רוויה (אחוזים)",
|
||||
"color.saturation_value": "רוויה ובהירות",
|
||||
"color.selected": "הצבע שנבחר",
|
||||
"color.step_down": "צעד למטה",
|
||||
"color.step_up": "צעד למעלה",
|
||||
"color.value": "ערך, הבהירות (אחוזים)",
|
||||
"config.column_filter_empty": "אין עמודות תואמות",
|
||||
"contact.components_count": "{count} רכיבים",
|
||||
"contact.enabled_label": "מופעל",
|
||||
@@ -1317,6 +1341,7 @@
|
||||
"dialog.dimension_name": "מידה: {name}",
|
||||
"dialog.edit_title": "עריכת {title}",
|
||||
"dialog.no_shown_body": "אין גוף מוצג לשינוי: הציגו גוף, או בחרו „גוף חדש”",
|
||||
"dialog.pattern_sketch_not_object": "בחרו גופים או פיצ'רים: סקיצה אינה אף אחד מהם. חזרו על העקומות שלה בעזרת המערך או השיקוף של הסקיצה עצמה, או בצעו לה שליפה קודם.",
|
||||
"dialog.select": "↖ בחירה",
|
||||
"dialog.selected_count": "↖ {count} נבחרו",
|
||||
"dialog.selection_guidance": "יש לבחור קלט כדי לשנות אותו. לחיצה על אובייקט שנבחר מסירה אותו; גם Ctrl/Cmd+לחיצה מחליפה את מצבו. לאחר בדיקת התצוגה המקדימה יש ללחוץ על אישור.",
|
||||
@@ -1374,26 +1399,243 @@
|
||||
"from the rule": "לפי הכלל",
|
||||
"help.apache": "רישיון Apache 2.0",
|
||||
"help.appearance.assign": "מתן צבע או מראה של חומר לגופים, לפאות או לרכיבים שנבחרו, בלי לשנות את משקלם. מתאים להבחנה בין חלקים או לתצוגה מקדימה של גימור.",
|
||||
"help.assembly.bom": "רישום חלקי התכן או הרכיב עם הכמויות שלהם לפי מק״ט, עם אפשרות לשמור את הרשימה כ־CSV או JSON. משמש כרשימת חלקים להזמנה ולהרכבה.",
|
||||
"help.attributions": "ייחוסים (ATTRIBUTION.md)",
|
||||
"help.build": "גרסה {version} · קומיט {commit} · נבנתה ב־{date}",
|
||||
"help.canvas.decal": "הנחת תמונה על פאה מישורית של המודל, כמו מדבקה. מתאים להצגת תווית, לוגו או דוגמה מודפסת על חלק.",
|
||||
"help.canvas.edit": "שינוי קנבס: מיקום, גודל, זווית, אטימות, שיקוף, נראות או שם. כך מיישרים תמונת ייחוס עם הסקיצה שמשרטטים מעליה.",
|
||||
"help.canvas.insert": "הנחת תמונת PNG או JPEG על מישור או פאה כייחוס שקוף למחצה. כך מעתיקים קווי מתאר מתצלום או מציור לסקיצה, כשהתמונה מותאמת למידה ידועה.",
|
||||
"help.component.break_link": "ניתוק רכיב מקושר מקובץ התכן שלו, תוך השארת הגופים כפי שהם. מתאים כשהחלק אינו אמור עוד להתעדכן בעקבות שינויים בקובץ המקורי.",
|
||||
"help.component.capture_position": "שמירת המיקומים של חלקים שהוזזו ידנית כמיקומים הקבועים שלהם. מתאים לאחר גרירת חלקים למקומם כשאין מפרק שמחזיק אותם.",
|
||||
"help.component.create": "הוספת רכיב חדש וריק לתכן, בתוך הרכיב הפעיל אלא אם נבחר רכיב אב אחר. כך מקצים לחלק חדש בהרכבה מקום משלו לגופים ולסקיצות.",
|
||||
"help.component.finish_edit": "שומר את החלק שנערך במקומו, חוזר להרכבה שלו ומעדכן ממנו את ההרכבה. יש להשתמש בו כשהשינויים בחלק המקושר הושלמו.",
|
||||
"help.component.from_bodies": "הפיכת כל גוף שנבחר לרכיב נפרד שנקרא על שם הגוף. מתאים להפיכת תכן של גופים נפרדים להרכבה שחלקיה ניתנים לחיבור ולהזזה.",
|
||||
"help.component.insert_design": "הוספת תכן שמור אחר כרכיב מקושר לקובץ שלו, כשהגופים המוצקים ממוקמים כפי שהם בו. כך משתמשים שוב בחלק בהרכבה ומקבלים שינויים מאוחרים יותר באמצעות עדכון קישורים.",
|
||||
"help.component.properties": "הצגת הנפח, המסה, מרכז המסה ומומנטי האינרציה של רכיב, לפי החומרים של הגופים שבו. מתאים לבדיקת המשקל והאיזון של הרכבה.",
|
||||
"help.component.revert_position": "החזרת חלקים שהוזזו ידנית למיקומם הקודם וביטול הזזות שמיקומן לא נלכד. כך מבטלים הזזות ניסיוניות בהרכבה.",
|
||||
"help.component.update_links": "קריאה מחדש של קובצי התכן המקושרים והחלפת גופים שהשתנו. מתאים לאחר עריכת חלק שמשמש בהרכבה זו.",
|
||||
"help.config.configure": "הוספת פרמטרים, פיצ'רים, חומרים או מראות כעמודות בטבלת התצורות. כך בונים גרסאות של תכן אחד, למשל מידות שונות של חלק.",
|
||||
"help.config.preview": "בדיקה שאחת משורות טבלת התצורות נבנית מחדש, בלי לשנות את התכן או את ההיסטוריה שלו. מתאים לפני מעבר לגרסה שאינך בטוח בה.",
|
||||
"help.config.rules": "הצגת הכללים של טבלת התצורות, השורות שלה והשורה הפעילה. כך רואים איך מוגדרות הגרסאות של התכן.",
|
||||
"help.config.table": "הצגת טבלת התצורות: שורה לכל גרסה, עמודה לכל פרמטר או פיצ'ר, ואם התכן עדיין תואם לשורה הפעילה. מתאים לסקירת הגרסאות של התכן.",
|
||||
"help.connect_note": "יש להפעיל מחדש כל עוזר כדי לטעון את שרת SolidCraft. לכל קובץ נשמר גיבוי בסיומת .bak לפני השינוי.",
|
||||
"help.connect_title": "חיבור עוזרי בינה מלאכותית",
|
||||
"help.construct.axis.edge": "יצירת ציר עזר לאורך מקצוע ישר או קו של סקיצה. משמש כציר לסיבוב, לשכפול מעגלי או למפרק.",
|
||||
"help.construct.axis.normal_to_face": "יצירת ציר עזר דרך נקודה, ניצב לפאה. משמש כציר שיוצא ישר מתוך משטח.",
|
||||
"help.construct.axis.through_cylinder": "יצירת ציר עזר דרך מרכז פאה של גליל, חרוט או טורוס, או מקצוע עגול. מתאים לסיבוב או לשכפול פיצ'רים סביב חלק עגול.",
|
||||
"help.construct.axis.two_planes": "יצירת ציר עזר במפגש של שני מישורים או שתי פאות שטוחות. מתאים כשהציר הדרוש הוא הקו שבין שתי פאות.",
|
||||
"help.construct.axis.two_points": "יצירת ציר עזר דרך שתי נקודות, קודקודים או נקודות סקיצה. מתאים לציר שעובר בין שני מיקומים ידועים.",
|
||||
"help.construct.plane.along_path": "יצירת מישור עזר ניצב למקצוע או לעקומה, במיקום לאורכם. משמש לשרטוט פרופיל לסחיפה או חתך של מסלול.",
|
||||
"help.construct.plane.at_angle": "יצירת מישור עזר מוטה בזווית ממישור או מפאה, סביב ציר או מקצוע. מתאים לסקיצות משופעות, כמו תמוכה בזווית.",
|
||||
"help.construct.plane.midplane": "יצירת מישור עזר באמצע בין שני מישורים או פאות שטוחות, או חוצה אותם במקום שבו הם נפגשים בזווית. משמש כמישור סימטריה לשיקוף.",
|
||||
"help.construct.plane.offset": "יצירת מישור עזר מקביל למישור או לפאה שטוחה, במרחק נתון או דרך נקודה. מתאים לשרטוט בגובה קבוע מעל פאה.",
|
||||
"help.construct.plane.perpendicular": "יצירת מישור עזר שמכיל קו או מקצוע וניצב למישור או לפאה. מתאים לשרטוט זקוף על המודל לאורך מקצוע.",
|
||||
"help.construct.plane.tangent": "יצירת מישור עזר שמשיק לגליל, לחרוט, לכדור או לטורוס בנקודה. מתאים לשרטוט על צידו של חלק עגול.",
|
||||
"help.construct.plane.three_points": "יצירת מישור עזר דרך שלוש נקודות. מתאים למישור שנקבע לפי מיקומים על המודל, כמו שלוש פינות.",
|
||||
"help.construct.plane.two_edges": "יצירת מישור עזר דרך שני מקצועות ישרים או קווים הנמצאים באותו מישור. מתאים למישור שחותך חלק, למשל דרך שני מקצועות מנוגדים.",
|
||||
"help.construct.point.along_path": "יצירת נקודת עזר במיקום לאורך מקצוע או עקומה. משמשת כנקודת ייחוס בחלק כלשהו של המסלול.",
|
||||
"help.construct.point.center": "יצירת נקודת עזר במרכז של מקצוע עגול, מעגל או קשת בסקיצה, כדור או טורוס. משמשת כנקודת ייחוס לחורים, לצירים ולמפרקים.",
|
||||
"help.construct.point.edge_plane": "יצירת נקודת עזר במקום שבו מקצוע או קו חוצים מישור או פאה שטוחה. משמשת לסימון המקום שבו מסלול חוצה מישור.",
|
||||
"help.construct.point.three_planes": "יצירת נקודת עזר במפגש של שלושה מישורים או פאות שטוחות. משמשת כנקודת ייחוס לפינה, גם כשאין במודל קודקוד.",
|
||||
"help.construct.point.two_edges": "יצירת נקודת עזר במפגש של שני מקצועות או קווים, או במקום שבו הם הכי קרובים. משמשת כנקודת ייחוס בפינה וירטואלית.",
|
||||
"help.construct.point.vertex": "יצירת נקודת עזר על קודקוד או נקודת סקיצה. משמשת כנקודת ייחוס שנשארת גם כשהסקיצה או הגוף שסביבה מוסתרים.",
|
||||
"help.contact.check": "הצגת זוגות החלקים בקבוצות מגע שחודרים זה לזה במיקומם הנוכחי. כך מוצאים התנגשויות לפני הנעת מפרקים או הפעלת חקר תנועה.",
|
||||
"help.contact.create": "קיבוץ שני חלקים או יותר לקבוצת מגע, שמונעת מגופיהם לחדור זה לזה בזמן תנועת המפרקים. מתאים לחלקים שצריכים לעצור כשהם נוגעים זה בזה, כגון מנוף כנגד המעצור שלו.",
|
||||
"help.contact.disable_all": "ביטול המגע, כך שמפרקים מונעים וחקר תנועה אינם נעצרים עוד במקום שבו החלקים נוגעים. כך מזיזים שוב חלקים בחופשיות או שומרים על תגובתיות של הרכבה גדולה.",
|
||||
"help.contact.edit": "שינוי קבוצת מגע: החלקים שבה, שמה או מצב ההשבתה שלה, עם אפשרות גם למחוק אותה. כך משנים אילו חלקים מנועים מלחדור זה לזה.",
|
||||
"help.contact.enable_all": "הכנסת כל חלקי ההרכבה לקבוצת מגע אחת, כך ששום שני חלקים אינם יכולים לחדור זה לזה בזמן תנועת המפרקים. מתאים לבדיקה מהירה של מנגנון שלם.",
|
||||
"help.contact.enable_sets": "הפעלת מגע לקבוצות המגע שהוגדרו, כך שמפרקים מונעים וחקר תנועה נעצרים במקום שבו חלקיהן היו חודרים זה לזה. כך מפעילים שוב את הקבוצות לאחר ביטול המגע.",
|
||||
"help.contact.list": "הצגת קבוצות המגע בתכן, החלקים בכל קבוצה והאם המגע פעיל. כך בודקים את הגדרת המגע לפני הנעת ההרכבה.",
|
||||
"help.document.inspect": "הצגת סקירה של התכן: הרכיבים, הגופים, הסקיצות, הפיצ'רים והפרמטרים שבו. מתאים כדי להתמצא בתכן שלא בנית בעצמך.",
|
||||
"help.document.units": "שינוי היחידות שבהן מוצגים אורכים בתכן, כמו mm או אינצ'ים. הגיאומטריה נשארת באותו גודל; רק התצוגה והמספרים הפשוטים משתנים.",
|
||||
"help.edit.checkpoint": "שמירת התכן, הסקיצה הפעילה והיסטוריית הביטולים כפי שהם עכשיו. מתאים לפני ניסיון מסוכן שאולי תרצה לחזור ממנו.",
|
||||
"help.edit.restore_checkpoint": "חזרה לנקודת שמירה, כולל היסטוריית הביטולים. מתאים כדי לבטל בצעד אחד את כל מה שנעשה מאז נקודת השמירה.",
|
||||
"help.explode.create": "יצירת תצוגה מפוצצת שמרחיקה את החלקים ממרכז ההרכבה או מזיזה אותם לפי ההזזות שנקבעו. כך מציגים כיצד מרכיבים את החלקים, לצורך הוראות או מצגות.",
|
||||
"help.face.delete": "מחיקת הפאות שנבחרו, כשהפאות השכנות סוגרות את הפער, או השארת הפתח פתוח כמשטח. מתאים להסרת עיגול, חור או בליטה שמפריעים.",
|
||||
"help.file.insert_mesh": "הוספת קובץ 3MF, STL, OBJ, PLY או glTF לתכן כגופי רשת משולשים ברכיב חדש. כך ממקמים מודל שהורד או נסרק לצד התכן כייחוס.",
|
||||
"help.file.insert_step": "הוספת קובץ STEP, IGES, FreeCAD או Rhino לתכן כגופים מוצקים ברכיב חדש, כשחלקי הרכבה הופכים לרכיבים מקוננים. כך מייבאים מודלים מספקים או מתוכנות CAD אחרות.",
|
||||
"help.file.save_mesh": "שמירת גופים כרשת משולשים מסוג STL, 3MF או OBJ, עם רמת החלקות שנבחרה לפאות מעוקלות. כך מכינים חלקים להדפסת תלת־ממד או לתוכנות שקוראות רשתות משולשים.",
|
||||
"help.file.send_to_slicer": "שמירת הגופים שנבחרו כקובץ 3MF ופתיחתו בסלייסר שנבחר. כך עוברים מהמודל להדפסה בצעד אחד.",
|
||||
"help.font_details": "הממשק משתמש בגופנים המובנים של egui (Ubuntu Light ו־Hack, תחת Ubuntu Font Licence ותחת רישיון MIT/Bitstream Vera; Noto Emoji וגופן סמלי האימוג'י, תחת OFL ו־MIT). טקסט בסקיצות משתמש ב־Liberation Sans (SIL OFL 1.1). חבילת הגופנים האופציונלית של Crafting Apps, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1), אינה כלולה בגרסאות של SolidCraft.",
|
||||
"help.fonts": "גופנים",
|
||||
"help.frame.member": "הצבת פרופיל, כמו צינור או פרופיל אלומיניום שחול, לאורך קווי סקיצה של מסגרת, איבר אחד לכל קו. מתאים לבניית מסגרות, מדפים ומבנים מולחמים.",
|
||||
"help.inspect.accessibility": "צביעת הפאות שכלי יכול להגיע אליהן מכיוון אחד, ואלה שאינו יכול. מתאים לבדיקת חלק לעיבוד שבבי או להזרקה מאותו צד.",
|
||||
"help.inspect.center_of_mass": "הצגת מרכז המסה של גופים, כל אחד לחוד וכולם יחד, בצפיפות אחידה. מתאים לבדיקת איזון ולזיהוי המקום שבו חלק יתהפך.",
|
||||
"help.inspect.colored_components": "מתן צבע זמני נפרד לכל רכיב, בלי לשנות את המראות. מתאים להבחנה במבט אחד בין חלקי ההרכבה.",
|
||||
"help.inspect.compare": "השוואה בין שני גופים והצגת המקומות שבהם לאחד יש חומר שאין לשני, עם נפח וסטייה. מתאים לבדיקת חלק ששונה או יובא מול המקור.",
|
||||
"help.inspect.continuity": "בדיקה עד כמה חלק המפגש בין פאות לאורך המקצועות: רווחים, שברים או קפיצות בעקמומיות, וצביעת התפרים. מתאים לאיתור מקומות שבהם משטחים לא מתחברים בצורה נקייה.",
|
||||
"help.inspect.curvature_comb": "שרטוט מסרקים על עקומות, מקצועות או פאות, ושיניהם מראות עד כמה הם מתעקלים. מתאים לאיתור אזורים שטוחים, שברים ועקמומיות לא אחידה.",
|
||||
"help.inspect.curvature_map": "צביעת פאות לפי עוצמת העקמומיות שלהן, באדום היכן שהרדיוס קטן. מתאים לאיתור נקודות חדות ולהערכת חלקות המשטח.",
|
||||
"help.inspect.draft": "צביעת פאות לפי זווית השיפוע שלהן ביחס לכיוון ההוצאה מהתבנית, וסימון אלה שהשיפוע שלהן קטן מדי. מתאים לבדיקת חלק לפני הזרקה או יציקה.",
|
||||
"help.inspect.environment_map": "הצגת המודל בגימור מחזיר אור, כמו מראה. מתאים להערכת הזרימה של משטחים לפי הדרך שבה ההשתקפויות עוברות עליהם.",
|
||||
"help.inspect.interference": "איתור גופים שחופפים והצגת כל חפיפה עם נפחה. מתאים לבדיקת הרכבה כדי למצוא חלקים שמתנגשים.",
|
||||
"help.inspect.isocurve": "שרטוט האיזו־עקומות של פאות, הרשת שעליה בנוי המשטח. מתאים כדי לראות איך המשטח זורם והיכן הקווים מצטופפים.",
|
||||
"help.inspect.measure": "מדידת אורכים, מרחקים, זוויות, שטחים ורדיוסים בין מה שנבחר, או נפח ומסה של גופים. מתאים לבדיקת מידות ומרווחים.",
|
||||
"help.inspect.minimum_radius": "איתור רדיוס העקמומיות הקטן ביותר של עקומות, מקצועות או פאות, והמקום שבו הוא נמצא. מתאים לוודא שכלי או נחיר יכולים לעקוב אחרי הצורה.",
|
||||
"help.inspect.section": "חיתוך התצוגה לאורך מישור וקווקו הפאות החתוכות, בלי לשנות את המודל. מתאים להצצה לתוך חלקים והרכבות.",
|
||||
"help.inspect.zebra": "הצגת פסים שחורים ולבנים המשתקפים על פאות המודל. מתאים להערכת חלקות: פסים שנקטעים או נשברים במקצוע מעידים על מעבר גרוע.",
|
||||
"help.joint.as_built": "חיבור שני חלקים במיקומם הנוכחי, ללא הזזת אף אחד מהם, והגדרת התנועה שעדיין מותרת להם. מתאים לחלקים שכבר מוקמו במיקומם הסופי.",
|
||||
"help.joint.cam": "קישור פיקה מסתובבת לעוקב, כך שהעוקב מחליק או מתנדנד כשקו המתאר של הפיקה עובר מתחתיו. מתאים לפיקות, לאקסצנטרים ולמנגנוני הנעת שסתומים.",
|
||||
"help.joint.create": "חיבור שני חלקים בראשיות המפרק שנבחרו והזזת החלק השני למקומו, כשסוג המפרק קובע את התנועה שעדיין מותרת להם. כך בונים הרכבה שחלקיה נעים כמו במנגנון האמיתי.",
|
||||
"help.joint.drive": "קביעת הזווית או המרחק של מפרק והזזת החלקים איתו בתוך גבולותיו, תוך מעקב של מפרקים מקושרים ולולאות סגורות. כך בודקים שהמנגנון נע כמתוכנן.",
|
||||
"help.joint.gear": "קישור שני מפרקים מסתובבים ביחס תמסורת, כך שהנעת אחד מסובבת את האחר. מתאים לגלגלי שיניים ישרים וטבעתיים, עם יחס לפי רדיוסי מעגלי החלוקה או מספרי השיניים.",
|
||||
"help.joint.limits": "קביעת גבולות מינימום ומקסימום לסיבוב או להחלקה של מפרק, או הסרת הגבולות. כך שומרים ציר, מחליק או מנוף בתוך טווח התנועה האמיתי שלו.",
|
||||
"help.joint.motion_link": "צימוד שני מפרקים ביחס ובהיסט, כך שהנעת אחד מזיזה את האחר. מתאים ליחס קבוע בין מפרקים שהכלים גלגל שיניים, מסרק וגלגל שיניים או בורג אינם מכסים.",
|
||||
"help.joint.origin": "הנחת ראשית מפרק בעלת שם על חלק: במרכז פאה או קצה עגול, באמצע מקצוע, בפינה או בנקודה. כך מכינים את מיקומי חיבור המפרקים, וראשית שנבחרה על פאה עוקבת אחריה כשגודל החלק משתנה.",
|
||||
"help.joint.rack_pinion": "קישור גלגל שיניים מסתובב למסרק מחליק, כך שהמסרק נע באורך הקשת שגלגל השיניים עובר על מעגל החלוקה. מתאים להנעות מסרק, למנגנוני היגוי ולבמות תנועה קוויות.",
|
||||
"help.joint.reach": "הזזת נקודה על חלק לעבר יעד על ידי שינוי המפרקים בשרשרת שלה, בתוך גבולותיהם. כך קובעים תנוחה של מנגנון לפי המיקום הרצוי של קצהו, כגון קצה זרוע רובוט.",
|
||||
"help.joint.rigid_group": "נעילת החלקים שנבחרו יחד כפי שהם, כך שינועו כיחידה אחת. מתאים לחלקים השייכים יחד ואינם נעים זה ביחס לזה.",
|
||||
"help.joint.screw": "קישור סיבוב והחלקה לפי פסיעה, כך שכל סיבוב מקדם באותו מרחק. מתאים לבורגי הנעה, לברגים ולכושים בעלי תבריג.",
|
||||
"help.library.apply": "החלת חומר או מראה מקובץ ספרייה מקומי על גופים, פאות או רכיבים. מתאים לשימוש חוזר בחומרים ששמרת מתכן אחר.",
|
||||
"help.library.export": "שמירת החומרים והמראות של התכן בקובץ ספרייה. מתאים לשיתוף או לשימוש חוזר בתכן אחר.",
|
||||
"help.library.inspect": "בדיקת קובץ ספרייה והצגת החומרים והמראות שבו, בלי לשנות את התכן. מתאים כדי לראות מה הספרייה מכילה לפני החלתה.",
|
||||
"help.licences": "רישיונות",
|
||||
"help.material.assign": "קביעת החומר שממנו עשויים הגופים שנבחרו, למשל פלדה, אלומיניום או ABS. כך המסה והמשקל תואמים את החלק האמיתי.",
|
||||
"help.material.properties.validate": "בדיקת כרטיס נתונים של חומר לאיתור מספרים לא עקביים וערכים חסרים. מתאים לפני הסתמכות על הנתונים לחישוב מסה או קשיחות.",
|
||||
"help.mesh.convert": "בנייה מחדש של גוף רשת, כמו STL, כגוף מוצק הניתן לעריכה עם פאות שטוחות וגליליות. מתאים לעריכת חלקים מכניים שיובאו כמו גוף שעוצב מאפס.",
|
||||
"help.mit": "רישיון MIT",
|
||||
"help.motion.study": "קביעת ערכי מפרקים בשלבים לאורך ציר זמן והפעלתם כהנפשה. כך צופים ברצף תנועות של מנגנון ובודקים מרווחים לאורך הדרך.",
|
||||
"help.motion.trace": "מעקב אחר המסלול של נקודה על חלק בזמן חקר תנועה או הנעת מפרק, ושמירתו כעקומת סקיצה תלת־ממדית לאחר האישור. כך רואים לאן מנגנון מגיע או בונים על בסיס מסלולו.",
|
||||
"help.notice": "NOTICE",
|
||||
"help.occurrence.ground": "עיגון חלק במקומו או שחרורו מחדש, כך שהמפרקים מניעים את החלקים האחרים סביבו. מתאים למסגרת או לבסיס שעליהם נבנית שאר ההרכבה.",
|
||||
"help.occurrence.move": "מזיז חלק בהרכבה רק בכיוונים שהמפרקים שלו מאפשרים. בחרו פאה של החלק, ואז גררו חץ או קשת זמינים.",
|
||||
"help.parameters.change": "פתיחת הטבלה של ערכים בעלי שם וביטויים שקובעים את מידות התכנון. כך משנים מידה במקום אחד וכל הפיצ'רים שמשתמשים בה מתעדכנים.",
|
||||
"help.parameters.export": "שמירת הפרמטרים של התכן כ־CSV או JSON. מתאים לעריכתם בגיליון אלקטרוני או להעברתם לתכן אחר.",
|
||||
"help.parameters.graph": "הצגת אילו פרמטרים ופיצ'רים משתמשים באילו אחרים, ואילו לולאות או שגיאות יש ביניהם. מתאים כדי לראות על מה ישפיע שינוי בפרמטר.",
|
||||
"help.parameters.import": "קריאת פרמטרים מ־CSV או JSON אל התכן, כולם או אף אחד. מתאים להבאת ערכים מגיליון אלקטרוני או מתכן אחר.",
|
||||
"help.parameters.move": "הזזת פרמטר משתמש לפני פרמטר אחר או אחריו ברשימה. מתאים כדי לשמור פרמטרים קשורים יחד.",
|
||||
"help.parts.fastener": "הוספת בורג, בורג עם אום, אום, דסקית, פין או מיסב סטנדרטיים בגודל שנבחר. בהנחה על חור, המחבר מתיישב בו עם מפרק, וכך אין צורך למדל מחברים בעצמכם.",
|
||||
"help.parts.insert": "הוספת חלק סטנדרטי מהמשפחה, בגודל ובאורך שנבחרו. בהנחה על שפת חור או על דופנו, החלק מתיישב על החור עם מפרק קשיח.",
|
||||
"help.parts.library": "פתיחת החלקים הסטנדרטיים: ברגים, ברגים עם אומים, אומים, דסקיות, בורגי קיבוע, פיני מיקום ומיסבים במידות סטנדרטיות. כך מוסיפים חלק סטנדרטי במקום למדל אותו בעצמכם.",
|
||||
"help.parts.resize": "שינוי הגודל או האורך של חלק סטנדרטי שהוכנס ובנייתו מחדש, כשהמפרקים שומרים אותו במקומו. מתאים כשבורג מתגלה כארוך מדי או כשחור דורש מידה אחרת.",
|
||||
"help.plastic.assign_rule": "הקצאת כלל פלסטיק לגופים, כך שפיצ'רי הפלסטיק שלהם יקבלו ממנו שיפוע ומרווח כברירת מחדל. מתאים כדי להגדיר חלק מוזרק פעם אחת לכל הפיצ'רים שלו.",
|
||||
"help.plastic.boss": "הוספת בליטה לבורג על פאה: עמוד עם חור אופציונלי, שיפוע, עיגול פינה בבסיס וצלעות תמיכה. מתאים לנקודות בורג בבתים מוזרקים או מודפסים.",
|
||||
"help.plastic.lip": "הוספת שפה או חריץ תואם לאורך שפת גוף חלול. מתאים כדי ששני חצאי בית יתמקמו זה על זה וייסגרו היטב.",
|
||||
"help.plastic.manage_rules": "יצירה ועריכה של כללי פלסטיק: חומר, עובי דופן, רדיוסים, מרווח ושיפוע. מתאים כדי לשמור על עקביות הפיצ'רים של חלק מוזרק.",
|
||||
"help.plastic.rest": "הוספת משען על פאה: כרית עגולה או מלבנית, מלאה או חלולה, עם שיפוע. משמש כתמיכה או כדוכן מרווח בבית מוזרק.",
|
||||
"help.plastic.snap_fit": "הוספת וו הצמדה על פאה, עם אורכו, עוביו והבליטה הנועלת. מתאים לחיבור חלקים בלחיצה בלי ברגים.",
|
||||
"help.pointcloud.insert": "הוספת סריקה בפורמט PLY, XYZ או PTS כענן נקודות לצד המודל. משמש כעזר למידול על סמך נתוני מדידה.",
|
||||
"help.sheet.convert": "הפיכת לוח או גוף חלול בעובי אחיד לגוף פח, עם כיפופים במקצועות שנבחרו. מתאים כדי להפוך חלק קיים לבר־פריסה.",
|
||||
"help.sheet.export_bend_table": "שמירת טבלת הכיפופים של גוף פח כ־CSV או JSON: זוויות, רדיוסים ומיקומי כיפוף בפריסה. מתאים למכונת הכיפוף או לסדנה.",
|
||||
"help.sheet.export_dxf": "שמירת הפריסה כ־DXF, עם קווי מתאר, קווי כיפוף והערות כיפוף אופציונליות. מתאים לחיתוך בלייזר, בפלזמה או בסילון מים.",
|
||||
"help.sheet.flange": "הוספת אוגן: לוח בסיס מסקיצה, דופן לאורך קו מתאר פתוח של סקיצה, או דופן מכופפת על מקצועות הפח. מתאים לבניית חלקי פח.",
|
||||
"help.sheet.flat_pattern": "יצירת הפריסה של גוף פח, עם הגודל, החיתוכים וקווי הכיפוף. מתאים לבדיקת הפח הפרוס לפני החיתוך.",
|
||||
"help.sheet.fold": "כיפוף פח לאורך קו סקיצה בזווית וברדיוס שנקבעו. מתאים לקיפול פח שטוח אחרי שנוספו בו חיתוכים.",
|
||||
"help.sheet.hem": "קיפול שפת פח חזרה על עצמה. מתאים לשפות בטוחות וקשיחות, בלי קצוות חדים.",
|
||||
"help.sheet.manage_rules": "יצירה ועריכה של כללי פח: עובי, רדיוס כיפוף, K-factor, חריצי הקלה ורווחים. מתאים כדי להתאים לחומר ולכלים של הסדנה שלך.",
|
||||
"help.sheet.path_flange": "הוספת שרשרת אוגנים לאורך שפת פח, לפי שרשרת פתוחה של קווי סקיצה. מתאים לפרופילים כמו צורת U או Z בצעד אחד.",
|
||||
"help.sheet.perforate": "הוספת שדה של חורים על כל הפח הפרוס, בתבנית מוסטת או מרובעת. מתאים לפתחי אוורור, לרשתות ולפאנלים קלים יותר.",
|
||||
"help.sheet.refold": "קיפול חוזר של גוף פח שנפתח. מתאים אחרי הוספת פיצ'רים לפח הפרוס.",
|
||||
"help.sheet.unfold": "פתיחת כל הכיפופים של גוף פח. מתאים להוספת חורים או חיתוכים שחייבים לעבור דרך כיפוף, ואז קיפול מחדש.",
|
||||
"help.sketch.arc.center_point": "משרטט קשת מעגלית סביב נקודת מרכז, מנקודת התחלה לנקודת סיום. מתאים כשמרכז הקשת ידוע, למשל רדיוס סביב חור או ציר.",
|
||||
"help.sketch.arc.tangent": "משרטט קשת שמתחילה בקצה של ישר או קשת וממשיכה משיקה לו. מתאים להמשכת שרשרת בעיקול חלק במקום בפינה.",
|
||||
"help.sketch.arc.three_point": "משרטט קשת מנקודת התחלה לנקודת סיום דרך נקודה שלישית. מתאים כשהקשת חייבת לעבור בנקודות נתונות ולא סביב מרכז ידוע.",
|
||||
"help.sketch.arc3d": "משרטט קשת מעגלית מדויקת במרחב דרך שלוש נקודות, כשסקיצה תלת־ממדית פעילה. מתאים לעיקולים במסלולים ובמסילות הנחיה שיוצאים ממישור הסקיצה.",
|
||||
"help.sketch.auto_constrain": "מוסיף את האילוצים שהסקיצה כמעט מקיימת ממילא, כמו אופקי, מקביל או מתלכד, ואז מוסיף מידות עד שהיא מוגדרת במלואה. מתאים לנעילת סקיצה גסה בצעד אחד.",
|
||||
"help.sketch.auto_constrain_from_datum": "פועל כמו אילוץ אוטומטי, אך מודד את המיקומים מנקודת ייחוס שבחרתם ולא מהראשית. מתאים כשהחלק מתוכנן מנקודת ייחוס אחת, כמו פינה או חור.",
|
||||
"help.sketch.blend_curve": "מחבר את הקצוות של שתי עקומות בספליין חלק המשיק לשתיהן, או גם רציף עקמומיות אם בוחרים. מתאים לגישור על פער בין עקומות בלי שבר.",
|
||||
"help.sketch.break": "מפצל עקומה לחלקים במקומות שבהם עקומות אחרות חוצות אותה, או בנקודות שמניחים עליה. מתאים כשחלק מהעקומה צריך אילוץ משלו או צריך להימחק לבדו.",
|
||||
"help.sketch.cancel": "יוצא מהסקיצה ומבטל כל מה ששונה בה מאז שנוצרה או נפתחה לעריכה. ביטול הפעולה מחזיר את השינויים.",
|
||||
"help.sketch.centerline": "מחליף ישרים בין ישרים רגילים לקווי מרכז, שהפרופילים מתעלמים מהם. השתמשו בקו מרכז כציר לסיבוב, לשיקוף או לאילוץ סימטריה.",
|
||||
"help.sketch.chamfer.distance_angle": "יוצר פאזה בפינה בין שני ישרים לפי מרחק לאורך הישר הראשון וזווית. מתאים כשהשרטוט נותן את הפאזה כאורך וזווית, כמו 2 mm × 30°.",
|
||||
"help.sketch.chamfer.equal_distance": "יוצר פאזה בפינה בין שני ישרים באותו מרחק לאורך שניהם. מתאים לפאזת 45° הרגילה בקו מתאר.",
|
||||
"help.sketch.chamfer.two_distance": "יוצר פאזה בפינה בין שני ישרים לפי מרחק נפרד לאורך כל ישר. מתאים לפאזות שאינן של 45°, הנתונות בשני אורכים.",
|
||||
"help.sketch.circle.center": "משרטט מעגל לפי מרכזו וקוטרו. מתאים לחורים, לבליטות ולמאפיינים עגולים אחרים שמרכזם ידוע.",
|
||||
"help.sketch.circle.three_point": "משרטט מעגל העובר בשלוש נקודות. מתאים כשהמעגל חייב לעבור בנקודות נתונות, למשל של גאומטריה קיימת.",
|
||||
"help.sketch.circle.three_tangent": "משרטט מעגל המשיק לשלושה ישרים, מעגלים או קשתות. מתאים להכנסת מעגל לחלל שבין שלוש עקומות, כמו המעגל החסום במשולש.",
|
||||
"help.sketch.circle.two_point": "משרטט מעגל משני קצות הקוטר שלו. מתאים כשנקודות הקצה של המעגל ידועות ולא מרכזו.",
|
||||
"help.sketch.circle.two_tangent": "משרטט מעגל בגודל נתון המשיק לשני ישרים, מעגלים או קשתות. מתאים לעיגול ברדיוס קבוע בין שתי עקומות.",
|
||||
"help.sketch.conic": "משרטט עקומת חתך חרוט בין שתי נקודות קצה, שצורתה נקבעת לפי נקודת קדקוד וערך rho. מתאים למעברים חלקים שמכוונים את מלאותם, משטוח ועד כמעט פינה חדה.",
|
||||
"help.sketch.constrainer": "מחיל את האילוץ שעקומה אחת או שתיים שנבחרו כמעט מקיימות, כמו אופקי, מקביל, משיק או שווה. מתאים לסידור סקיצה שנוצרה ביד, יחס אחד בכל פעם.",
|
||||
"help.sketch.constraint.coincident": "גורם לנקודה להתלכד עם נקודה אחרת, עם עקומה או עם ציר הסקיצה. מתאים לסגירת פערים בפרופיל או להנחת נקודה על ישר.",
|
||||
"help.sketch.constraint.collinear": "גורם לשני ישרים לשכב על ישר אחד. מתאים ליישור קצוות מקוטעים, כמו שני צדי מגרעת.",
|
||||
"help.sketch.constraint.concentric": "נותן לשני מעגלים או קשתות אותו מרכז. מתאים לטבעות, לשקעי ברגים ולצירים עם מדרגות.",
|
||||
"help.sketch.constraint.curvature": "גורם לשתי עקומות שנפגשות בנקודת קצה להמשיך באותה עקמומיות (G2). מתאים כשחיבור משיק אינו חלק מספיק, למשל על משטחים גלויים.",
|
||||
"help.sketch.constraint.equal": "גורם לישרים להיות באותו אורך, ולמעגלים ולקשתות באותו רדיוס. מתאים כדי שמידה אחת תניע כמה מאפיינים תואמים.",
|
||||
"help.sketch.constraint.fix": "מקבע נקודות או עקומות במקומן, או משחרר אותן שוב. מתאים לגאומטריה שאסור שתזוז בגרירה או בפתרון הסקיצה.",
|
||||
"help.sketch.constraint.horizontal_vertical": "גורם לישר, או לישר שבין שתי נקודות, להיות אופקי או אנכי, לפי הקרוב יותר. מתאים ליישור קו מתאר לצירי הסקיצה.",
|
||||
"help.sketch.constraint.midpoint": "מציב נקודה באמצע ישר, או גורם לנקודות האמצע של שני ישרים להיפגש. מתאים למירכוז גאומטריה על קצה.",
|
||||
"help.sketch.constraint.parallel": "גורם לשני ישרים להיות מקבילים. מתאים לצלעות שחייבות להישאר מקבילות כשמידות אחרות משתנות.",
|
||||
"help.sketch.constraint.perpendicular": "גורם לשני ישרים להיפגש בזווית ישרה. מתאים לפינות ישרות בין ישרים שאינם על צירי הסקיצה.",
|
||||
"help.sketch.constraint.polygon": "הופך שרשרת סגורה של ישרים למצולע משוכלל: צלעות שוות וכל פינה על מעגל אחד. מתאים להפיכת מצולע שצויר ביד למשוכלל ולשמירה על כך.",
|
||||
"help.sketch.constraint.symmetry": "גורם לשתי נקודות או עקומות להיות תמונת מראה זו של זו סביב ישר או נקודה. מתאים לשמירה על פרופיל סימטרי כששינוי נעשה בצד אחד.",
|
||||
"help.sketch.constraint.tangent": "גורם לשתי עקומות לגעת זו בזו כמשיקות, כמו ישר וקשת. מתאים לחיבורים חלקים בלי שבר.",
|
||||
"help.sketch.construction": "מחליף עקומות בין גאומטריה רגילה לגאומטריית עזר, שהפרופילים מתעלמים ממנה. השתמשו בעקומות עזר לתכנון, לייחוסים ולמידות.",
|
||||
"help.sketch.construction_line": "יצירת ישר עזר אינסופי דרך שתי נקודות, לתכנון הסקיצה בלי לפצל את הפרופילים.",
|
||||
"help.sketch.construction_line.angle": "יצירת ישר עזר אינסופי בזווית מציר X של הסקיצה. יש לבחור נקודה ולהקליד זווית או לבחור כיוון.",
|
||||
"help.sketch.construction_line.bisector": "יש לבחור שני ישרים נחתכים בסקיצה ואז אחד משני חוצי הזווית. התוצאה עוקבת אחר עריכת ישרי המקור.",
|
||||
"help.sketch.construction_line.horizontal": "יצירת ישר עזר אופקי אינסופי דרך נקודה. האילוץ האופקי נשמר בעריכות מאוחרות יותר.",
|
||||
"help.sketch.construction_line.parallel": "יש לבחור ישר בסקיצה ואז למקם ישר עזר אינסופי מקביל. לחיצה ימנית מאפשרת לבחור ייחוס אחר.",
|
||||
"help.sketch.construction_line.perpendicular": "יש לבחור ישר בסקיצה ואז למקם ישר עזר אינסופי ניצב. לחיצה ימנית מאפשרת לבחור ייחוס אחר.",
|
||||
"help.sketch.construction_line.tangent_at": "יצירת משיק בנקודה על מעגל או קשת מעגלית, או בנקודת קצה של ספליין פתוח או חתך חרוט פתוח. יש לבחור את העקומה ואז את נקודת ההשקה.",
|
||||
"help.sketch.construction_line.tangent_external": "יש לבחור מעגל או קשת מעגלית, נקודה חיצונית ואז פתרון למשיק. התצוגה המקדימה מציגה רק נקודות השקה על הקשת המצוירת.",
|
||||
"help.sketch.construction_line.tangent_two": "יש לבחור שני מעגלים או קשתות מעגליות ואז משיק משותף בתצוגה המקדימה. נקודות ההשקה חייבות להיות על העקומות המצוירות.",
|
||||
"help.sketch.construction_line.vertical": "יצירת ישר עזר אנכי אינסופי דרך נקודה. האילוץ האנכי נשמר בעריכות מאוחרות יותר.",
|
||||
"help.sketch.copy": "מעתיק את עקומות הסקיצה והנקודות שנבחרו, יחד עם האילוצים והמידות שביניהן. אפשר להדביק אותן בסקיצה הזו או באחרת.",
|
||||
"help.sketch.create": "מתחיל סקיצה דו־ממדית חדשה על מישור או על פאה שטוחה של המודל. כל שליפה, סיבוב וסחיפה מתחילים בסקיצה.",
|
||||
"help.sketch.cut": "מעתיק את גאומטריית הסקיצה שנבחרה ומוחק אותה מהסקיצה, בצעד ביטול אחד. אפשר להדביק במקום אחר בסקיצה הזו או באחרת.",
|
||||
"help.sketch.dimension": "מוסיף מידה מניעה: אורך, מרחק, זווית, רדיוס או קוטר, לפי מה שבוחרים. מקלידים ערך או שם פרמטר והסקיצה עוקבת אחריו.",
|
||||
"help.sketch.edit": "פותח סקיצה קיימת לעריכה. המאפיינים שנבנו עליה מתעדכנים כשמסיימים את הסקיצה.",
|
||||
"help.sketch.ellipse": "משרטט אליפסה לפי מרכזה, קצה הציר הראשי שלה ונקודה בצד הציר המשני. מתאים לפתחים אליפטיים, לזיזים ולצורות עגולות מוארכות אחרות.",
|
||||
"help.sketch.equation_curve": "משרטט עקומה מנוסחאות על פני טווח: x(t) ו־y(t), או y = f(x). הנוסחאות יכולות להשתמש בפרמטרים והעקומה עוקבת אחריהם: לגל סינוס, לספירלה או לאבולבנטה של שן גלגל שיניים.",
|
||||
"help.sketch.extend": "מאריך ישר או קשת עד העקומה הקרובה ביותר בדרכם, או מגדיל שתי עקומות עד שייפגשו. מתאים לסגירת פערים בפרופיל אחרי גיזום או עריכה.",
|
||||
"help.sketch.fillet": "מעגל את הפינה שבה נפגשים שני ישרים או קשתות בקשת ברדיוס נתון. פינות שמעגלים יחד חולקות רדיוס אחד.",
|
||||
"help.sketch.finish": "יוצא מהסקיצה וחוזר למודל. הפרופילים הסגורים שלה מוכנים אז לשליפה, לסיבוב ולמאפיינים אחרים.",
|
||||
"help.sketch.finish_auto_constrain": "מריץ אילוץ אוטומטי על הסקיצה ואז מסיים אותה. מתאים להשארת סקיצה מוגדרת במלואה בצעד אחד.",
|
||||
"help.sketch.fit_curves_to_section": "חותך רשת משולשים או גוף מוצק במישור הסקיצה ומתאים ישרים וקשתות לחתך. מתאים לשחזור חלק שנסרק או יובא כסקיצה הניתנת לעריכה.",
|
||||
"help.sketch.include_3d": "מביא קצוות, קדקודים ועקומות של סקיצות אחרות אל הסקיצה הזו כייחוסים מקושרים, ומשטח אותם למישור שלה. מתאים לבנייה על גאומטריה שאינה במישור הסקיצה.",
|
||||
"help.sketch.infinite": "מחליף ישרים בין ישרים רגילים לישרי עזר אינסופיים שחוצים את כל התצוגה. מתאים לייחוסי תכנון שלעולם אינם קצרים מדי.",
|
||||
"help.sketch.insert_dxf": "קריאת העקומות של שרטוט DXF לתוך סקיצה, בקנה המידה, בסיבוב ובמיקום שנקבעו. כך ממשיכים לעבוד על שרטוט דו־ממדי מתוכנה אחרת, כגון קו מתאר לחיתוך בלייזר.",
|
||||
"help.sketch.insert_svg": "קריאת הנתיבים של שרטוט SVG לתוך סקיצה, בקנה המידה, בסיבוב ובמיקום שנקבעו. כך הופכים לוגו או קו מתאר וקטורי לעקומות שניתן לשחל.",
|
||||
"help.sketch.inspect": "פותח דוח על הסקיצה הפתוחה: כמה דרגות חופש נותרו והאם היא מאולצת במלואה. השתמשו בו כדי לגלות מה עדיין זז לפני שמסיימים את הסקיצה.",
|
||||
"help.sketch.intersect": "מוסיף את העקומות או הנקודות שבהן גופים, פאות, קצוות או סקיצות אחרות חותכים את מישור הסקיצה. הן נשארות מקושרות ועוקבות אחר המודל כשהוא משתנה.",
|
||||
"help.sketch.intersection_curve": "יוצר עקומות תלת־ממדיות במקום שבו שני גופים או פאות נפגשים, מקושרות אליהם. מתאים למסלולים או למסילות הנחיה שעוקבים אחר המודל.",
|
||||
"help.sketch.isoparametric_curve": "יוצר עקומה תלת־ממדית לאורך כיוון U או V של פאה דרך נקודה שבוחרים, מקושרת לפאה. מתאים למסלול או לקו פיצול שעוקבים אחר המשטח.",
|
||||
"help.sketch.line": "משרטט ישרים מחוברים נקודה אחר נקודה, כשרשרת פתוחה או כקו מתאר סגור. זה הכלי הבסיסי לרוב הפרופילים.",
|
||||
"help.sketch.line.midpoint": "משרטט ישר מנקודת האמצע שלו אל אחד הקצוות, כשהקצה השני משוקף. מתאים לישרים הממורכזים סביב נקודה, כמו קצה סימטרי.",
|
||||
"help.sketch.line3d": "משרטט ישרים מחוברים בין נקודות במרחב, כשסקיצה תלת־ממדית פעילה. מתאים למסלולים ולמסגרות שיוצאים ממישור הסקיצה.",
|
||||
"help.sketch.mirror": "משקף עקומות ונקודות של סקיצה סביב ישר או ציר ומוסיף אילוצי סימטריה. מתאים לשרטוט חצי מפרופיל סימטרי והשלמתו.",
|
||||
"help.sketch.move": "מזיז או מסובב עקומות ונקודות של סקיצה, או עותק שלהן. מתאים לשינוי מיקום גאומטריה תוך שמירה על צורתה ועל האילוצים.",
|
||||
"help.sketch.offset": "יוצר עותק של שרשרת עקומות במרחק קבוע, בצד אחד או בשניהם. מתאים לדפנות, לקווי מתאר ולמרווחים; המרחק נשאר מידה הניתנת לעריכה.",
|
||||
"help.sketch.paste": "מדביק בסקיצה הפעילה גאומטריית סקיצה שהועתקה או נגזרה. אפשר למקם אותה בנקודה או להזיז אותה בהיסט.",
|
||||
"help.sketch.pattern.circular": "מעתיק גאומטריית סקיצה סביב נקודת מרכז, על פני מעגל שלם או זווית נתונה. מתאים למעגלי ברגים, לחישורים ולשיניים.",
|
||||
"help.sketch.pattern.rectangular": "מעתיק גאומטריית סקיצה בשורות ובעמודות במרווחים קבועים. מתאים לרשתות של חורים, חריצים או פתחי אוורור.",
|
||||
"help.sketch.point": "מציב נקודת סקיצה. משמש כייחוס למידות, לאילוצים, למרכזי חורים או למאפיינים מאוחרים יותר.",
|
||||
"help.sketch.point3d": "מציב נקודה במרחב, כשסקיצה תלת־ממדית פעילה. משמש כייחוס לעקומות ולמסלולים תלת־ממדיים.",
|
||||
"help.sketch.polygon.circumscribed": "משרטט מצולע משוכלל סביב מעגל, בגודל שנקבע ממרכזו ועד אמצע צלע. מתאים כשהרוחב בין הצלעות ידוע, כמו באום משושה.",
|
||||
"help.sketch.polygon.edge": "משרטט מצולע משוכלל משני קצותיה של צלע אחת. מתאים כשאורך הצלע ומיקומה ידועים.",
|
||||
"help.sketch.polygon.inscribed": "משרטט מצולע משוכלל בתוך מעגל, בגודל שנקבע ממרכזו ועד פינה. מתאים כשהגודל בין הפינות ידוע.",
|
||||
"help.sketch.project": "מביא קצוות, פאות, קדקודים ועקומות של סקיצות אחרות אל הסקיצה הזו, מוטלים על מישורה. הם נשארים מקושרים ועוקבים אחר המודל כשהוא משתנה.",
|
||||
"help.sketch.project_to_surface": "מטיל עקומות של סקיצות אחרות לאורך הנורמל של הסקיצה הזו על פאה, כעקומות תלת־ממדיות מקושרות. מתאים להנחת לוגו, קו פיצול או מסלול על משטח מעוקל.",
|
||||
"help.sketch.rectangle.center": "משרטט מלבן לפי מרכזו ואחת מפינותיו. מתאים לקווי מתאר הממורכזים סביב נקודה, כמו הראשית.",
|
||||
"help.sketch.rectangle.rounded": "משרטט מלבן ובו ארבע פינות מעוגלות ברדיוס אחד. מתאים ללוחות, למכסים ולפתחים עם פינות מעוגלות.",
|
||||
"help.sketch.rectangle.three_point": "משרטט מלבן לפי צלע אחת ונקודה בצד הנגדי. מתאים למלבנים שנטויים ביחס לצירי הסקיצה.",
|
||||
"help.sketch.rectangle.two_point": "משרטט מלבן משתי פינות נגדיות. מתאים לקווי המתאר של לוחות, גושים וכיסים.",
|
||||
"help.sketch.scale": "משנה קנה מידה של עקומות ונקודות בסקיצה בפקטור סביב נקודת בסיס. מתאים לשינוי גודל של חלק מהסקיצה בלי לשרטט אותו מחדש.",
|
||||
"help.sketch.slot.arc_center": "משרטט חריץ מעוקל ברוחב נתון לאורך קשת שנקבעת לפי מרכזה, תחילתה וסופה. מתאים לחריצי כוונון סביב ציר.",
|
||||
"help.sketch.slot.arc_three_point": "משרטט חריץ מעוקל ברוחב נתון לאורך קשת העוברת בשלוש נקודות. מתאים כשמסלול החריץ חייב לעבור בנקודות נתונות.",
|
||||
"help.sketch.slot.center_point": "משרטט חריץ ישר ברוחב נתון ממרכזו ועד מרכז קשת הקצה האחת. מתאים לחריצים הממורכזים סביב נקודה.",
|
||||
"help.sketch.slot.center_to_center": "משרטט חריץ ישר ברוחב נתון בין מרכזי קשתות שני קצותיו. מתאים לחריצים שמידותיהם ממרכז למרכז, כמו חריצי כוונון לברגים.",
|
||||
"help.sketch.slot.overall": "משרטט חריץ ישר ברוחב נתון מקצהו החיצוני האחד אל השני. מתאים כשהאורך הכולל של החריץ הוא העיקר.",
|
||||
"help.sketch.spline.control_point": "משרטט ספליין מעוקב שצורתו נקבעת על ידי נקודות בקרה שהוא אינו עובר בהן. מתאים לעקומות חלקות וזורמות שמעצבים בהזזת הנקודות.",
|
||||
"help.sketch.spline.control_point_5": "משרטט ספליין ממעלה 5 שצורתו נקבעת על ידי נקודות בקרה. מתאים כשעקומות צריכות להתחבר בעקמומיות חלקה יותר, למשל במשטחים מעוצבים גלויים.",
|
||||
"help.sketch.spline.fit_point": "משרטט ספליין חלק שעובר בכל נקודה שמניחים, פתוח או סגור. מתאים למעקב אחר צורה דרך נקודות ידועות.",
|
||||
"help.sketch.spline3d": "משרטט עקומה חלקה במרחב דרך נקודות, כשסקיצה תלת־ממדית פעילה. מתאים למסלולי סחיפה ולמסלולי כבלים שיוצאים ממישור הסקיצה.",
|
||||
"help.sketch.spun_profile": "יוצר במישור הסקיצה את קו המתאר שגוף סוחף כשהוא מסתובב סביב ציר. מתאים לקבלת צללית של חלק מחרטה לצורך סיבוב או שרטוט.",
|
||||
"help.sketch.text": "כותב טקסט בסקיצה בגופן, בגובה ובזווית שבוחרים, ואפשר שהמילים יעקבו אחר פרמטרים. שלפו אותו או השתמשו בהבלטה לתוויות ולכיתובים.",
|
||||
"help.sketch.transform": "משנה קנה מידה, מסובב ומזיז גאומטריית סקיצה סביב נקודת מרכז בצעד אחד. מתאים לשינוי מיקום וגודל של בחירה בבת אחת.",
|
||||
"help.sketch.trim": "מסיר את קטע העקומה שבין החיתוכים הקרובים ביותר סביב המקום שלחצתם עליו. מתאים לניקוי ישרים חופפים עד לפרופיל סגור.",
|
||||
"help.solid.align": "הזזת הגופים שנבחרו כך שנקודה, פאה או מישור שלהם יפגשו נקודה, פאה או מישור במקום אחר. מתאים להצמדת חלק לחלק אחר בלי למדוד את המרחק.",
|
||||
"help.solid.boundary_fill": "יצירת מוצקים מהאזורים הסגורים בין גופי כלי חופפים, תוך מילוי האזורים שנבחרו בלבד. כך בונים צורה מהחלל שכמה גופים תוחמים יחד.",
|
||||
"help.solid.bounding_solid": "יצירת תיבה שחוסמת את הגופים שנבחרו, עם אפשרות לתוספת שוליים. כך רואים את המידות הכוללות של חלק או יוצרים את חומר הגלם שממנו הוא יעובד.",
|
||||
"help.solid.box": "יצירת תיבה לפי אורך, רוחב וגובה, החל מנקודת פינה או ממורכזת סביב נקודה. מתאים ליצירה מהירה של גוש, מציין מקום או גוף לחיתוך מאפיינים בתוכו.",
|
||||
"help.solid.chamfer": "חיתוך המקצועות שנבחרו בשיפוע ישר במרחק שנקבע. כך שוברים מקצועות חדים או מקלים על הכנסה של פין או בורג.",
|
||||
"help.solid.coil": "יצירת גוף סלילי, כגון קפיץ, לפי קוטר, מספר כריכות, גובה או פסיעה וחתך עגול או מרובע. מתאים לקפיצים, לסלילים ולבליטות סליליות.",
|
||||
"help.solid.combine": "איחוד גופים, חיסורם מגוף יעד או השארת הנפח המשותף להם בלבד, עם אפשרות לשמור את גופי הכלי. מתאים למיזוג חלקים, לחיתוך צורה אחת בעזרת אחרת או למציאת החפיפה בין שני גופים.",
|
||||
"help.solid.cone": "יצירת חרוט ממעגל בסיס וגובה, או חרוט קטום כשנקבע גם רדיוס בחלק העליון. מתאים לצורות מתחדדות, למשפכים, לשיקועים חרוטיים ולחודים.",
|
||||
"help.solid.cylinder": "יצירת גליל לפי רדיוס או קוטר וגובה, הניצב בנקודה לאורך ציר. מתאים לצירים, לפינים, לבליטות גליליות ולגולמים עגולים.",
|
||||
"help.solid.draft": "הטיית הפאות שנבחרו בזווית שנקבעה, הנמדדת ממישור ניטרלי. מתאים לחלקים יצוקים או מוזרקים, כדי שישתחררו מהתבנית.",
|
||||
"help.solid.emboss": "הבלטת פרופילי סקיצה, כגון טקסט או לוגו, מתוך פאה או השקעתם בתוכה. מתאים לאותיות, לתוויות ולסימונים על פאות שטוחות או עגולות.",
|
||||
"help.solid.extrude": "דחיפת פרופיל של סקיצה לתלת־ממד לאורך מרחק, להוספה או להסרה של חומר. כך הופכים קו מתאר שטוח לגוש, לבליטה או לכיס.",
|
||||
"help.solid.fillet": "עיגול המקצועות שנבחרו במעבר מעגלי חלק ברדיוס שנקבע. כך מרככים מקצועות חדים לטובת חוזק, נוחות או מראה.",
|
||||
"help.solid.hole": "קידוח חור עגול בקוטר שנקבע בנקודה שנבחרה על פאה. מתאים לחורי מעבר לברגים, לפינים ולפתחים עגולים פשוטים אחרים.",
|
||||
@@ -1402,20 +1644,60 @@
|
||||
"help.solid.move": "הזזה או סיבוב של הגופים שנבחרו, או של עותק שלהם, במרחק ובזווית שנקבעו. מתאים לשינוי מיקום של גוף או ליצירת גוף נוסף במקום אחר.",
|
||||
"help.solid.offset_face": "דחיפת הפאות שנבחרו פנימה או החוצה במרחק שנקבע, והפאות שסביבן מתאימות את עצמן. כך מעבים דופן, מעמיקים כיס או מגביהים בליטה בלי לערוך את הסקיצה.",
|
||||
"help.solid.pattern.circular": "שכפול הפריטים שנבחרו סביב ציר, לפי המספר והזווית הכוללת שנקבעו. מתאים למעגלי ברגים, לחישורים, לצלעות קירור ולשיניים.",
|
||||
"help.solid.pattern.path": "העתקת פיצ'רים או גופים לאורך מסלול סקיצה, לפי כמות ומרווח. מתאים לחורים לאורך מקצוע מעוקל או לחלקים לאורך מסילה.",
|
||||
"help.solid.pattern.rectangular": "שכפול הפריטים שנבחרו בכיוון אחד או בשניים, לפי המספר והמרווח שנקבעו. מתאים לשורות ולרשתות של חורים, צלעות, פינים או רגליות.",
|
||||
"help.solid.pipe": "יצירת צינור עגול לאורך נתיב של עקומות סקיצה, מלא או חלול עם עובי דופן. מתאים לצינורות, לחוטים, לכבלים ולמסילות.",
|
||||
"help.solid.press_pull": "הוספה או הסרה של חומר בגרירת פאה, או עיגול מקצועות בגרירתם. מתאים לשינויים מהירים ישירות על המודל.",
|
||||
"help.solid.remove": "הוצאת הגופים שנבחרו מהתכנון מנקודה זו בציר הזמן והלאה; השלבים הקודמים שומרים אותם. מתאים להסרת גוף עזר, כמו כלי חיתוך שכבר אין בו צורך.",
|
||||
"help.solid.replace_face": "העברת הפאות השטוחות שנבחרו אל מישור או אל פאה מקבילה, והגוף מתארך או מתקצר כדי להגיע אליהם. מתאים ליישור פאה בקו אחד עם חלק אחר או עם מישור עזר.",
|
||||
"help.solid.revolve": "סיבוב פרופיל של סקיצה סביב ציר ליצירת גוף מוצק עגול. מתאים לגלים, לכפתורים, לקערות ולכל חלק שעגול סביב קו מרכז.",
|
||||
"help.solid.rib": "הוספת צלע דקה לאורך עקומת סקיצה פתוחה, הנמשכת עד לפאות הבאות של הגוף. כך מחזקים דפנות ופינות, למשל בחלקים יצוקים או מודפסים.",
|
||||
"help.solid.scale": "הגדלה או הקטנה של הגופים שנבחרו לפי מקדם, זהה בכל הכיוונים או שונה לכל ציר. מתאים לשינוי גודל של צורה מיובאת או להתחשבות בהתכווצות.",
|
||||
"help.solid.shell": "חלילת גוף מוצק תוך השארת דפנות בעובי שנקבע, עם אפשרות לפתוח את הפאות שנבחרו. מתאים לקופסאות, למכסים ולחלקים אחרים בעלי דופן דקה.",
|
||||
"help.solid.sphere": "יצירת כדור לפי רדיוס או קוטר סביב נקודת מרכז. מתאים לכדורים, לכפתורי אחיזה ולקצוות מעוגלים.",
|
||||
"help.solid.split_body": "פיצול גוף לגופים נפרדים בעזרת מישור, פאה של גוף אחר או קו בסקיצה. מתאים ליצירת חלקים שמודפסים, מעובדים או נצבעים כל אחד בנפרד.",
|
||||
"help.solid.split_face": "פיצול הפאות שנבחרו לאורך מישור, פאה של גוף אחר או עקומות של סקיצה, בלי לחתוך את הגוף. כך נותנים לחלק מפאה שיפוע, צבע או היסט משלו.",
|
||||
"help.solid.sweep": "גרירת פרופיל של סקיצה לאורך מסלול ליצירת גוף מוצק. מתאים לצינורות, למסילות, לידיות ולכל חלק בעל חתך קבוע שעוקב אחרי עקומה.",
|
||||
"help.solid.thread": "הוספת תבריג מטרי לפי ISO לפאה גלילית, כתבריג סמלי או כחיתוך בגוף. מתאים לברגים, לחורים בעלי תבריג ולחלקי הברגה מודפסים.",
|
||||
"help.solid.torus": "יצירת טבעת לפי רדיוס ראשי סביב הציר שלה ורדיוס משני לחתך העגול. מתאים לטבעות אטימה, לידיות ולבליטות טבעתיות עגולות.",
|
||||
"help.solid.web": "הוספת דופן דקה לאורך כל עקומת סקיצה פתוחה, כשכל אחת נמשכת עד לפאות הבאות של הגוף. מתאים לרשת דפנות תמיכה בתוך מארזים ומגשים.",
|
||||
"help.surface.blend": "יצירת משטח שמגשר בין מקצועות של שני גופים, משיק או רציף בעקמומיות לשניהם. מתאים לחיבור חלק בין שני משטחים מעל רווח.",
|
||||
"help.surface.boundary": "יצירת משטח שממלא לולאה של שניים עד ארבעה עקומות סקיצה, או רשת של עקומות. מתאים ללוחות בצורה חופשית שמוגדרים לפי הקצוות שלהם.",
|
||||
"help.surface.extend": "הארכת משטח מעבר לקצוותיו, במרחק נתון או עד מישור או פאה. מתאים כדי שמשטחים יחפפו לפני גיזום או תפירה.",
|
||||
"help.surface.extrude": "דחיפת עקומות או פרופילים של סקיצה לאורך מרחק למשטח, דפנות בלבד בלי מכסים. מתאים לדפנות דקות ולכלי חיתוך או פיצול.",
|
||||
"help.surface.fair": "החלקת פנים הפאות החופשיות כשהקצוות שלהן נשארים במקומם. מתאים ליישור בליטות והשתקפויות גליות במשטח.",
|
||||
"help.surface.loft": "יצירת משטח שעובר דרך שני חתכים או יותר לפי הסדר, בלי מכסים. מתאים לקליפות ולמעברים בין צורות שונות.",
|
||||
"help.surface.match": "בנייה מחדש של קצה משטח כך שייפגש עם קצה של גוף אחר, בהתאמת משיק או עקמומיות. מתאים לסגירה חלקה של תפר בין שני משטחים.",
|
||||
"help.surface.offset": "יצירת עותק של פאות במרחק לאורך הנורמלים שלהן, כגוף משטח חדש. מתאים לקליפות, למרווחים או לצדו השני של דופן.",
|
||||
"help.surface.patch": "מילוי אזור סקיצה או לולאה סגורה של מקצועות בפאה, שטוחה או מעוקלת בעדינות. מתאים לסגירת חורים בגוף משטח.",
|
||||
"help.surface.reverse_normal": "היפוך פאות של גוף משטח כך שצדן החיצוני יפנה לכיוון ההפוך. מתאים לפני עיבוי או תפירה כשהפאות פונות פנימה.",
|
||||
"help.surface.revolve": "סיבוב עקומות או פרופילים של סקיצה סביב ציר למשטח, בלי מכסים. מתאים לקליפות עגולות כמו אהילים, קערות וזרבובים.",
|
||||
"help.surface.ruled": "יצירת רצועה של קווים ישרים היוצאים משרשרת מקצועות, בכיוון הנורמל של הפאה, המשיק או בזווית. מתאים לדפנות שיפוע, לאזורי מעבר ולמשטחי חלוקה.",
|
||||
"help.surface.stitch": "תפירת גופי משטח זה לזה לאורך המקצועות המשותפים, לגוף מוצק אם הם סוגרים נפח. מתאים להפיכת קבוצת משטחים לגוף אחד.",
|
||||
"help.surface.sweep": "הזזת עקומות או פרופילים של סקיצה לאורך מסלול למשטח, בלי מכסים. מתאים למרזבים, לפסי קישוט ולצורות דקות אחרות שעוקבות אחרי מסלול.",
|
||||
"help.surface.thicken": "מתן עובי לגוף משטח והפיכתו לגוף מוצק. מתאים ליצירת חלקים להדפסה או לעיבוד שבבי ממשטחים.",
|
||||
"help.surface.trim": "חיתוך משטח בעזרת מישור, משטח אחר או עקומות סקיצה, ושמירת הצד שנבחר. מתאים לגיזום משטחים לצורה לפני תפירה.",
|
||||
"help.surface.unstitch": "הפרדת פאות של גוף לגופי משטח נפרדים; גוף מוצק מתפרק למשטחים. מתאים לעיבוד מחדש של פאות בודדות בגוף.",
|
||||
"help.surface.untrim": "הסרת חורים מפאה, או החזרת הגבול החיצוני שלה לגבולות הטבעיים של המשטח. מתאים לשחזור המשטח המלא אחרי גיזום.",
|
||||
"help.third_party": "רישיונות צד שלישי",
|
||||
"help.timeline.compute_all": "בנייה מחדש של כל הפיצ'רים בציר הזמן מההתחלה. מתאים לרענון המודל ולבדיקה אילו פיצ'רים נכשלים.",
|
||||
"help.timeline.delete": "מחיקת הפיצ'רים שנבחרו מציר הזמן; מחיקת סקיצה מוחקת גם את הפיצ'רים שנבנו ממנה. מתאים להסרת שלב שכבר אין בו צורך.",
|
||||
"help.timeline.dependents": "הצגת הפיצ'רים שיימחקו יחד עם פיצ'ר, ואלה שייכשלו בלעדיו. מתאים לפני מחיקה או שינוי של פיצ'ר.",
|
||||
"help.timeline.play": "הפעלה מחדש של הפיצ'רים שנותרו, אחד בכל פעם, עם השהיה של חצי שנייה לאחר כל בנייה מחדש. להפסקה יש להפעיל שוב את הפקודה או ללחוץ על Escape; מעבר לסוף מתבצע מיד.",
|
||||
"help.view.apply": "סיבוב התצוגה לכיוון סטנדרטי כמו חזית, מבט עליון או איזומטרי, או לתצוגה שמורה בשם. מתאים להתבוננות במודל מזווית קבועה.",
|
||||
"help.view.delete": "מחיקת תצוגה שמורה. המודל אינו משתנה.",
|
||||
"help.view.fit": "זום והזזה כך שכל המודל, או הבחירה, ימלאו את התצוגה. מתאים כשהמודל יצא מהטווח הנראה.",
|
||||
"help.view.grid": "הצגה או הסתרה של הרשת בחלון התצוגה. משמשת כמדריך לגודל ולכיוון בזמן המידול.",
|
||||
"help.view.ground_shadow": "הצגה או הסתרה של צל המודל על הקרקע. מתאים כדי להעריך גובה ומיקום ביתר קלות.",
|
||||
"help.view.home": "החזרת התצוגה לכיוון הבית והתאמת המודל לחלון. מתאים לחזרה מהירה לתצוגה מוכרת.",
|
||||
"help.view.list": "הצגת רשימת התצוגות השמורות בתכן. מתאים כדי למצוא תצוגה ששמרת קודם.",
|
||||
"help.view.navigate": "סיבוב, הזזה או זום של התצוגה בצעדים, כמו רבע סיבוב שמאלה. מתאים להזזה מדויקת של המצלמה במקום גרירה.",
|
||||
"help.view.navigation_bar": "הצגה או הסתרה של סרגל הניווט בתחתית חלון התצוגה. אפשר להסתיר אותו לשטח נוסף, או להציג אותו כדי להגיע אל כלי התצוגה בעכבר.",
|
||||
"help.view.rename": "מתן שם חדש לתצוגה שמורה. התצוגה עצמה נשארת כפי שהיא.",
|
||||
"help.view.save": "שמירת מיקום המצלמה הנוכחי כתצוגה בשם בתכן. מתאים לחזרה לאותה זווית בהמשך, למשל לצילומי מסך.",
|
||||
"help.view.spin": "הקפת המודל בתצוגה באופן רציף עד ללחיצה או למקש הבא. מתאים להצגת מודל מכל הצדדים.",
|
||||
"help.view.tool": "נעילת כלי מצלמה, מסלול, הזזה או זום, כך שגרירה בכפתור השמאלי של העכבר מזיזה את התצוגה עד שמכבים אותו. מתאים למשטח מגע או כשאין כפתור עכבר אמצעי.",
|
||||
"help.view.visual_style": "החלפת אופן הציור של המודל: מוצלל עם מקצועות או בלעדיהם, מסגרת תיל, או עם מקצועות מוסתרים. מסגרת תיל מאפשרת לראות פנימה, ומוצלל נותן מראה נקי.",
|
||||
"history.sketch_under_constrained": "אילוצים חסרים ({count} דרגות חופש)",
|
||||
"history.sketch_under_constrained_one": "אילוצים חסרים (דרגת חופש {count})",
|
||||
"hole_presets.confirm_delete": "אישור מחיקה",
|
||||
@@ -1592,6 +1874,10 @@
|
||||
"material.selection.mixed": "חומרים שונים",
|
||||
"measure.at": "מיקום",
|
||||
"measure.item": "פריט {number}",
|
||||
"measure.quick_copied": "המדידה הועתקה",
|
||||
"measure.quick_copy": "לחיצה מעתיקה את המדידה",
|
||||
"measure.quick_edges": "{count} מקצועות",
|
||||
"measure.quick_faces": "{count} פאות",
|
||||
"messages.ago_h": "לפני {n} שע'",
|
||||
"messages.ago_min": "לפני {n} דק'",
|
||||
"messages.ago_s": "לפני {n} שנ'",
|
||||
@@ -1625,6 +1911,7 @@
|
||||
"nav.hfss.help": "Alt וגרירה שמאלית מזיזים, Shift+Alt וגרירה שמאלית מבצעים זום, Ctrl וגרירה שמאלית משטח ריק מסובבים",
|
||||
"nav.inventor.help": "גרירה אמצעית מזיזה, Shift וגרירה אמצעית מסובבים, Ctrl וגרירה אמצעית מבצעים זום, גרירה ימנית מסובבת",
|
||||
"nav.maya.help": "Alt וגרירה שמאלית מסובבים, Alt וגרירה אמצעית מזיזים, Alt וגרירה ימנית מבצעים זום; גם גרירה אמצעית מזיזה",
|
||||
"nav.nx.help": "גרירה בלחצן האמצעי מסובבת, Shift+האמצעי מזיז את התצוגה (ב-NX: אמצעי + ימני), Ctrl+האמצעי מקרב ומרחיק (ב-NX: אמצעי + שמאלי); גרירה בלחצן הימני לא מזיזה את המצלמה",
|
||||
"nav.openscad.help": "גרירה שמאלית על שטח ריק מסובבת, Shift וגרירה שמאלית בוחרים במלבן, גרירת גאומטריית סקיצה עורכת אותה; גרירה ימנית או אמצעית מזיזה, Shift וגרירה ימנית או אמצעית מבצעים זום",
|
||||
"nav.perspective.sketch": "עריכת סקיצה משתמשת בתצוגה אורתוגרפית. יש לסיים את הסקיצה כדי לעבור לפרספקטיבה.",
|
||||
"nav.right_drag_orbits.help": "כבוי: גרירה בכפתור הימני לא מזיזה את המצלמה, והכפתור הימני רק פותח את תפריט ההקשר. בחירת מיפוי העכבר SolidWorks מכבה זאת.",
|
||||
@@ -1744,6 +2031,11 @@
|
||||
"not a move": "זו אינה הזזה",
|
||||
"not a number": "לא מספר",
|
||||
"open a sketch first": "יש לפתוח סקיצה תחילה",
|
||||
"parameters.apply_live": "להחיל כל שינוי ביציאה מהשדה שלו",
|
||||
"parameters.apply_live_tip": "כבוי: השינויים ממתינים עד ל„החל” או „אישור”, ואז התכן נבנה מחדש פעם אחת עבור כולם. „ביטול” או Escape משליכים אותם.",
|
||||
"parameters.held": "{count} שינויים ממתינים ל„החל”",
|
||||
"parameters.held_hint": "עריכת ביטויים ויחידות. השינויים ממתינים ל„החל” או ל„אישור”.",
|
||||
"parameters.held_one": "שינוי אחד ממתין ל„החל”",
|
||||
"parts.automatic_name": "אוטומטי",
|
||||
"parts.dimension.across_flats": "מידת מפתח",
|
||||
"parts.dimension.bore": "קוטר קדח",
|
||||
@@ -1766,6 +2058,8 @@
|
||||
"parts.family.set_screw": "בורג אלן ללא ראש, קצה שטוח",
|
||||
"parts.family.socket_head_cap_screw": "בורג ראש גלילי עם משושה פנימי",
|
||||
"parts.family.washer": "דסקית שטוחה",
|
||||
"parts.holes": "חורים (אופציונלי)",
|
||||
"parts.placement_hint": "בחרו חור אחד או יותר כדי להושיב חלק בכל אחד, או לחצו אישור כדי למקם אותו בראשית",
|
||||
"pattern.alignment_2": "יישור 2",
|
||||
"pattern.alignment_hint": "הספירה כוללת את המקור. מרכוז מאזן את העותקים; היפוך בוחר את הצד שמקבל את העותק הנוסף כשהסך זוגי.",
|
||||
"pattern.direction_1": "כיוון 1",
|
||||
@@ -1818,6 +2112,8 @@
|
||||
"prefs.bottom_centre": "למטה במרכז",
|
||||
"prefs.bottom_right": "למטה מימין",
|
||||
"prefs.browser": "עץ התכן",
|
||||
"prefs.browser_eye_left": "סמל העין ליד חץ הקיפול",
|
||||
"prefs.browser_eye_left_note": "שורות עץ התכן מציגות את סמל העין ליד חץ הקיפול, כמו קודם, במקום בעמודה בקצה הימני של השורות.",
|
||||
"prefs.browser_reveal_on_hover": "הצגה בריחוף",
|
||||
"prefs.browser_show_note": "״מוצג״ משאיר את הדפדפן על המסך. ״הצגה בריחוף״ מסתיר אותו עד שהמצביע מגיע למקומו או ללשונית הדקה בקצהו השמאלי, והוא נשאר פתוח כל עוד המצביע בתוכו או שתפריט ממנו פתוח.",
|
||||
"prefs.browser_shown": "מוצג",
|
||||
@@ -1837,6 +2133,8 @@
|
||||
"prefs.ctrl_cmd": "Ctrl / Cmd",
|
||||
"prefs.curved_surfaces": "משטחים מעוקלים",
|
||||
"prefs.curves": "משטחים מעוקלים",
|
||||
"prefs.dark_parts_shading": "שמירה על צורת חלקים כהים",
|
||||
"prefs.dark_parts_shading_help": "הצללת התצוגה באור ליניארי עם תאורת שמיים רכה, כך שפאות כהות שומרות על מעבר גוונים במקום להפוך לשחורות",
|
||||
"prefs.dead_zone_note": "הפס המקווקו הוא האזור המת: תנועה בתוכו לא נלקחת בחשבון.",
|
||||
"prefs.default": "ברירת מחדל",
|
||||
"prefs.design": "ברירות מחדל לתכן",
|
||||
@@ -1851,6 +2149,8 @@
|
||||
"prefs.edges": "מקצועות והצללה",
|
||||
"prefs.extend": "הרחבה",
|
||||
"prefs.extra_navigation": "Ctrl עם גרירה שמאלית במקום ריק מסובב את המבט; החזקת Space מזיזה אותו.",
|
||||
"prefs.extrude_view_isometric": "סיבוב התצוגה לאיזומטרית בפתיחת שליפה",
|
||||
"prefs.extrude_view_return": "חזרה לתצוגה הקודמת בסגירת שליפה",
|
||||
"prefs.follows_os": "לפי מערכת ההפעלה",
|
||||
"prefs.font": "גופן",
|
||||
"prefs.font_fallback": "תווים שחסרים בגופן הנבחר מוצגים בגופן המובנה, כך שאף תווית לא מופיעה כריבוע ריק.",
|
||||
@@ -1866,8 +2166,11 @@
|
||||
"prefs.graphics_card_auto": "אוטומטי",
|
||||
"prefs.graphics_card_missing": "הכרטיס הגרפי השמור אינו זמין; נעשה שימוש באפשרות אוטומטי.",
|
||||
"prefs.graphics_card_restart": "ייכנס לתוקף אחרי הפעלה מחדש של SolidCraft. WGPU_ADAPTER_NAME גובר על בחירה זו.",
|
||||
"prefs.graphics_card_unused": "כרטיס המסך השמור לא שימש לחלון זה; הכרטיס שבשימוש מוצג בעזרה › אודות ובשורת המצב. נסו אוטומטי, או הגדירו את WGPU_ADAPTER_NAME לחלק ייחודי משם הכרטיס.",
|
||||
"prefs.graphics_note": "איזון בין מהירות לחלקות. כל בחירה מציגה את השפעתה על דוגמה.",
|
||||
"prefs.graphics_presets_note": "הגדרות קבועות מראש קובעות יחד את הבחירות שלמטה.",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out": "הסתרת סמלי אילוצים בהקטנה",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out_note": "סמלי האילוצים נעלמים כשהשרטוט מוקטן מספיק כדי שלא יעמיסו על התצוגה. כבוי: הם נשארים בגודל מסך קבוע בכל זום.",
|
||||
"prefs.history": "ציר הזמן",
|
||||
"prefs.history_origin_bodies": "הצגת הראשית והגופים למעלה",
|
||||
"prefs.history_origin_bodies_note": "ההיסטוריה משמאל או מתחת לדפדפן מתחילה בתיקיית הגופים של הרכיב הפעיל ובראשית, עם סמלי העין והתפריטים כמו בדפדפן. ההיסטוריה למטה לא משתנה.",
|
||||
@@ -1878,6 +2181,8 @@
|
||||
"prefs.history_sketches_note": "כשהסקיצות מוגדרות ל„מתחת לפיצ'ר שלהן”, ציר הזמן משמאל מציג כל סקיצה רמה אחת פנימה, מתחת לפיצ'ר הראשון שנבנה ממנה, בכל פעם שהוא רחב מספיק להצגת שמות. ציר הזמן בתחתית שומר תמיד על סדר היצירה.",
|
||||
"prefs.history_sketches_under_feature": "מתחת לפיצ'ר שלהן",
|
||||
"prefs.hold_stop_snapping": "החזקה לעצירת ההצמדה",
|
||||
"prefs.home_fit_size": "גודל בתצוגת בית ובהתאמה",
|
||||
"prefs.home_fit_size_note": "כמה מהתצוגה המודל ממלא כשתצוגת בית, התאמה, עיצוב שנפתח או שינוי תצוגה בניווט ממסגרים אותו, בין אם ההגדרה שלמטה פעילה ובין אם לא. 100 %: ממלא את התצוגה שבין הלוחות, המצפן וסרגל הניווט.",
|
||||
"prefs.icons_only": "סמלים בלבד",
|
||||
"prefs.imported_file": "קובץ מיובא",
|
||||
"prefs.in_browser": "בעץ התכן",
|
||||
@@ -1886,13 +2191,20 @@
|
||||
"prefs.interface_language": "שפת הממשק",
|
||||
"prefs.interface_note": "איך SolidCraft נראה והיכן חלקיו ממוקמים.",
|
||||
"prefs.interval_minutes": "{n} דק׳",
|
||||
"prefs.invert_navigator_arrows": "היפוך חצי סיבוב קוביית התצוגה",
|
||||
"prefs.invert_navigator_arrows_note": "החצים סביב הקובייה מחוויים את המצלמה לכיוון שהחץ מצביע, כמו ב-Fusion ו-Inventor: החץ שמשמאל מצביע ימימה ומניע את המצלמה ימימה. כבוי: החץ מסובב את הקובייה אל הצד שבו הוא יושב, כך שחץ שמאל מניע את המצלמה שמאלה. חצי הגלילה המעוגלים אינם מושפעים.",
|
||||
"prefs.keep_work_on_tab_switch": "השארת תיבות דו־שיח וכלים פתוחים במעבר בין עיצובים",
|
||||
"prefs.keep_work_on_tab_switch_note": "כל לשונית עיצוב שומרת את תיבת הדו־שיח או הכלי הפתוחים בה, עם מה שבחרת והקלדת בהם, ואת לשונית סרגל הכלים שלה. הם מחכים לך כשתחזור לעיצוב. כבוי: מעבר בין עיצובים מבטל אותם ומציג את הלשונית מודל.",
|
||||
"prefs.labels": "תוויות",
|
||||
"prefs.language_system": "מערכת",
|
||||
"prefs.layout": "פריסה",
|
||||
"prefs.layout_note": "הפריסה הדחוסה מצמידה חלוניות לשולי החלון. שקיפות עץ התכן זמינה בפריסה הצפה. את צד העוזר אפשר לשנות בעמוד העוזר.",
|
||||
"prefs.left": "שמאל",
|
||||
"prefs.left_click": "לחיצה שמאלית",
|
||||
"prefs.line_drag_draws_one": "לחיצה וגרירה משרטטות קו אחד",
|
||||
"prefs.line_drag_draws_one_note": "בכלי הקו, לחיצה, גרירה ושחרור משרטטים קו אחד מנקודת הלחיצה עד נקודת השחרור, והוא מסתיים שם. לחיצות עדיין משרטטות שרשרת. כבוי: גרירה מציבה נקודה היכן שמשחררים, כמו לחיצה.",
|
||||
"prefs.line_hover_tangent_arc": "השהיה על הנקודה האחרונה של קו עוברת לקשת משיקה",
|
||||
"prefs.line_hover_tangent_arc_note": "בכלי הקו, אחרי ציור מקטע, התרחקו מהנקודה האחרונה של השרשרת, חזרו אליה והחזיקו את הסמן עליה ללא תנועה: הלחיצה הבאה תסיים קשת משיקה, ואותה מחווה מחזירה לקווים. כבוי: השהיה שם אינה עושה דבר.",
|
||||
"prefs.linked_designs": "תכנים מקושרים",
|
||||
"prefs.live_input": "קלט חי",
|
||||
"prefs.live_preview": "תצוגה מקדימה חיה",
|
||||
@@ -1906,6 +2218,9 @@
|
||||
"prefs.max_file_size_step": "קובצי STEP וייבוא",
|
||||
"prefs.max_file_size_web": "יישום הדפדפן פותח קובצי STEP וייבוא עד 512 MB וקובצי תכן עד 256 MB: לשונית דפדפן אינה יכולה להכיל קבצים גדולים יותר. ביישום למחשב ניתן להעלות מגבלות אלה.",
|
||||
"prefs.megabytes": "MB",
|
||||
"prefs.menu_grid": "סמלים גדולים",
|
||||
"prefs.menu_list": "רשימה",
|
||||
"prefs.menus": "תפריטים",
|
||||
"prefs.minutes": "דקות",
|
||||
"prefs.minutes_suffix": " דק'",
|
||||
"prefs.mouse": "עכבר ומשטח מגע",
|
||||
@@ -1913,6 +2228,8 @@
|
||||
"prefs.mouse_mapping": "מיפוי העכבר",
|
||||
"prefs.navigation": "ניווט",
|
||||
"prefs.navigation_note": "איך העכבר, משטח המגע והעכבר התלת־ממדי מזיזים את המבט.",
|
||||
"prefs.navigator_fit": "התאמת המודל לאחר שינוי תצוגה בניווט התצוגה",
|
||||
"prefs.navigator_fit_note": "לחיצה על פאה, פינה או חץ בקובייה, או על ציר בגיזמו, גם מביטה אל מרכז המודל מהמרחק האחד שמכיל אותו מכל צד (הכדור החוסם שלו). תצוגת בית משתמשת באותו זום ובאותו מרכז כל עוד זה פעיל, כך שתצוגות שנבחרות אחריה רק מסתובבות. כבוי: התצוגה מסתובבת במקומה ושומרת על היעד ועל הזום.",
|
||||
"prefs.network_host_remove": "הסרה",
|
||||
"prefs.network_locations": "התרת מיקומי רשת בתכנים",
|
||||
"prefs.network_locations_note": "כבוי: קבצים מקושרים של תכן במחשב אחר (\\\\server\\share) נפתחים רק מהשרתים הרשומים כאן, או אחרי שמתירים שרת כשנשאלים.",
|
||||
@@ -1925,10 +2242,16 @@
|
||||
"prefs.origin_plane_names": "שמות מישורי הראשית",
|
||||
"prefs.origin_plane_names_note": "השמות המוצגים בדפדפן, בתיבות הדו־שיח וברשימות. {top} הוא XY, {front} הוא XZ ו־{right} הוא YZ, כש־Z למעלה. פקודות, סקריפטים ותכנונים שמורים שומרים על XY, XZ ו־YZ.",
|
||||
"prefs.overall_speed": "מהירות כללית",
|
||||
"prefs.parameter_list_rows": "שורות ברשימת הפרמטרים",
|
||||
"prefs.parameter_list_rows_tip": "חץ למטה בשדה ערך ריק מציג את הפרמטרים, המועדפים תחילה, עד מספר זה. מספר קטן יותר שומר על רשימה קלה בתכנון גדול.",
|
||||
"prefs.persistent_ribbon_pressed": "הדגשת פקודות פעילות ברצועת הכלים",
|
||||
"prefs.persistent_ribbon_pressed_help": "הדגשת פקודות ברצועת הכלים כל עוד ההשפעות שלהן פעילות. כבו אפשרות זו כדי לשמור על המראה הניטרלי הקודם ועל עזרת הפקודות.",
|
||||
"prefs.perspective_fov": "שדה ראייה",
|
||||
"prefs.placement": "מיקום",
|
||||
"prefs.prefer_free_sketch_points": "העדפת נקודות סקיצה ניתנות להזזה כשנקודות חופפות",
|
||||
"prefs.preview_choices": "תצוגה מקדימה של הבחירות שלך",
|
||||
"prefs.print_face_highlight": "הדגשת פאת ההדפסה",
|
||||
"prefs.print_face_highlight_tip": "עד כמה חזק צובעים ומקיפים את פאת ההדפסה של גוף בתצוגה. 0 % אינו מציג הדגשה.",
|
||||
"prefs.profile_active": "פרופיל פעיל",
|
||||
"prefs.profile_applied": "הפרופיל הוחל.",
|
||||
"prefs.profile_changed": "ההגדרות השתנו מאז שהפרופיל נשמר. „שמירה“ מכניסה אותן לפרופיל.",
|
||||
@@ -1950,9 +2273,13 @@
|
||||
"prefs.quality_fastest": "המהיר ביותר",
|
||||
"prefs.quality_slowest": "האיטי ביותר",
|
||||
"prefs.quality_smoother": "חלק יותר",
|
||||
"prefs.quick_measure": "מדידה מהירה בפינת התצוגה",
|
||||
"prefs.quick_measure_note": "מציג את מידות הבחירה בפינה הימנית התחתונה של התצוגה, מעל ההיסטוריה: אורך מקצוע (או Ø ו-R למקצוע עגול), שטח פאה, מיקום נקודה, המרחק והזווית בין שני פריטים, והסכום של כמה מקצועות או פאות. לחיצה מעתיקה אותו.",
|
||||
"prefs.render_previous_geometry_budget": "שימוש בתקציב הגאומטריה הקודם לתצוגה מקדימה של רינדור",
|
||||
"prefs.render_previous_geometry_budget_help": "שחזור מגבלת הגאומטריה הקבועה הקודמת (512 MiB במחשב שולחני של 64 סיביות, 128 MiB בפלטפורמות אחרות) במקום התקציב המבוסס על ההתקן.",
|
||||
"prefs.reports_saved": "{n} שמורים",
|
||||
"prefs.ribbon_click_ends_tool": "לחיצה על הלחצן של הכלי הפעיל מסיימת אותו",
|
||||
"prefs.ribbon_click_ends_tool_note": "לחיצה על לחצן הסרט המודגש של כלי השרטוט שבשימוש מסיימת את הכלי, כך שלחיצות בתצוגה בוחרות שוב. כבוי: הלחיצה מפעילה את הכלי מחדש.",
|
||||
"prefs.ribbon_reveal": "הצגת תוצאות חיפוש בסרט",
|
||||
"prefs.ribbon_reveal_note": "מעבר עם הסמן מעל תוצאה בחיפוש פקודות מראה היכן הפקודה נמצאת בסרט: הלשונית, הכפתור או השורה שלה בתפריט הנפתח של לוח. פקודה שהופעלה מהחיפוש מהבהבת שם, ופקודה פעילה מתפריט נפתח מסמנת את הלוח שלה.",
|
||||
"prefs.right_click": "לחיצה ימנית",
|
||||
@@ -1963,6 +2290,8 @@
|
||||
"prefs.search_empty": "אין הגדרות תואמות",
|
||||
"prefs.select": "בחירה",
|
||||
"prefs.select_one_item": "בחירת פריט אחד",
|
||||
"prefs.select_other_hidden": "בחירת גאומטריה מוסתרת באמצעות בחירה אחרת",
|
||||
"prefs.select_other_hidden_help": "מופעל: כולל גופים, סקיצות וקצוות מוסתרים בקרבת הסמן. כבוי: שימוש ברשימה המקורית של גאומטריה גלויה מתחת לסמן.",
|
||||
"prefs.selecting": "בחירה",
|
||||
"prefs.shift": "Shift",
|
||||
"prefs.shift_add_ctrl_toggle": "Shift מוסיף בלבד; Ctrl / Cmd מחליף מצב",
|
||||
@@ -1974,11 +2303,18 @@
|
||||
"prefs.sketch_align_points_note": "בזמן השרטוט, נקודה מתיישרת אופקית עם נקודת סקיצה אחת ואנכית עם אחרת בו-זמנית, עם קו עזר מנוקד, והלחיצה שומרת את שני היישורים. כבוי: רק עם הנקודה הקודמת, ציר אחד בכל פעם.",
|
||||
"prefs.sketch_conflict_colour": "גאומטריה סותרת בצבע הסתירה",
|
||||
"prefs.sketch_conflict_colour_note": "כשאילוצי סקיצה סותרים, העקומות והנקודות שאילוץ כושל מחזיק מצוירות גם הן בצבע הסתירה, לא רק הסמל או המידה שלו. כבוי: הן שומרות על צבעיהן הרגילים.",
|
||||
"prefs.sketch_construction_lines": "כלי ישרי עזר מורחבים",
|
||||
"prefs.sketch_exit_view": "בסיום סקיצה",
|
||||
"prefs.sketch_exit_view.keep": "שמירה על התצוגה הנוכחית",
|
||||
"prefs.sketch_exit_view.previous": "חזרה לתצוגה הקודמת",
|
||||
"prefs.sketch_exit_view.unless_rotated": "חזרה אלא אם התצוגה סובבה",
|
||||
"prefs.sketch_exit_view_note": "לאן התצוגה עוברת אחרי סיום סקיצה, ביטול או Esc כפול.",
|
||||
"prefs.sketch_face_activates_part": "שרטוט על פאה של חלק הופך את החלק לפעיל",
|
||||
"prefs.sketch_face_activates_part_note": "שרטוט שמתחיל על פאה של גוף ברכיב אחר מפעיל קודם את הרכיב הזה, כך שהשרטוט שייך לו ונשאר עם החלק בסייר. החלק נשאר פעיל אחר כך. כבוי: השרטוט שייך לרכיב הפעיל.",
|
||||
"prefs.sketch_open_look_at": "הפניית התצוגה אל הסקיצה בפתיחתה",
|
||||
"prefs.sketch_open_look_at_note": "כבוי: יצירה או עריכה של סקיצה משאירות את התצוגה כפי שהיא. «מבט אל» מפנה את התצוגה אל הסקיצה כשרוצים.",
|
||||
"prefs.sketch_recent_snap": "הצמדה אוטומטית למרכזים ולנקודות אמצע אחרונים",
|
||||
"prefs.sketch_recent_snap_note": "בזמן שרטוט, הסמן נצמד למקום שבו נחתכים קווי העזר של שני מרכזי המעגלים או נקודות האמצע של קצוות ישרים האחרונים. כבוי: קווי העזר נשארים לתצוגה בלבד והסמן אינו זז.",
|
||||
"prefs.sketch_selection": "סקיצה ובחירה",
|
||||
"prefs.sketch_selection_heading": "סקיצה ובחירה",
|
||||
"prefs.sketch_selection_note": "איך סקיצות נצמדות ואיך לחיצות בוחרות.",
|
||||
@@ -1988,6 +2324,8 @@
|
||||
"prefs.sketch_tab_always_note": "לשונית הסקיצה נשארת ברצועה, מיד אחרי מודל, גם כשאין סקיצה פתוחה. כלי השרטוט בה מתחילים אז סקיצה על המישור או הפאה שנבחרו, או על המישור שתבחרו בהמשך, והכלי מוכן בה.",
|
||||
"prefs.sketch_tracking_guides": "קווי עזר ליישור מרכזים ונקודות אמצע",
|
||||
"prefs.sketch_tracking_guides_note": "יש לרחף עם הסמן מעל מרכז מעגל או נקודת אמצע של צלע ישרה, ואז להזיז אותו אופקית או אנכית כדי להציג קו עזר מקווקו זמני.",
|
||||
"prefs.sketch_tracking_points": "קווי עזר ליישור מנקודות קצה ומפינות בזמן שרטוט",
|
||||
"prefs.sketch_tracking_points_note": "כשכלי שרטוט ממתין לנקודה, ריחוף מעל קצה של קו או קשת, פינה של מלבן או נקודה חופשית מציג את אותו קו עזר מקווקו זמני כמו במרכז או בנקודת אמצע. כבוי: מרכזים ונקודות אמצע בלבד.",
|
||||
"prefs.sketching": "שרטוט סקיצות",
|
||||
"prefs.snap_drawing_note": "בזמן ציור או גרירה של נקודת סקיצה.",
|
||||
"prefs.source": "מקור",
|
||||
@@ -2004,6 +2342,24 @@
|
||||
"prefs.status_error": "שגיאה",
|
||||
"prefs.status_selected": "נבחר",
|
||||
"prefs.status_warning": "אזהרה",
|
||||
"prefs.structure.appearance": "מראה",
|
||||
"prefs.structure.appearance_note": "צבעים, טקסט ונגישות.",
|
||||
"prefs.structure.in_profile": "כלול בפרופיל",
|
||||
"prefs.structure.layout": "פריסה",
|
||||
"prefs.structure.layout_note": "מיקום חלקי החלון.",
|
||||
"prefs.structure.look": "מראה",
|
||||
"prefs.structure.measure_pointer": "מדידה ומצביע",
|
||||
"prefs.structure.mouse3d": "עכבר תלת־ממדי",
|
||||
"prefs.structure.mouse3d_note": "SpaceMouse ו־SpaceNavigator.",
|
||||
"prefs.structure.navigation_note": "עכבר ומשטח מגע. לעכבר התלת־ממדי יש עמוד משלו.",
|
||||
"prefs.structure.profile": "פרופיל",
|
||||
"prefs.structure.profile_edited": "השתנה מאז השמירה",
|
||||
"prefs.structure.profile_hover": "נשמר בפרופילי הגדרות",
|
||||
"prefs.structure.scale_percent": "{percent}%",
|
||||
"prefs.structure.sketch": "סקיצה",
|
||||
"prefs.structure.tools": "כלים",
|
||||
"prefs.structure.tools_note": "אופן הפעולה של כלי המידול.",
|
||||
"prefs.structure.work": "עבודה",
|
||||
"prefs.supersampling_brief": "מצייר את המבט גדול יותר ומקטין אותו: חד מאוד, וכבד יותר.",
|
||||
"prefs.tab_accent_note": "צבע ההדגשה עוקב אחר הלשונית הפעילה",
|
||||
"prefs.theme_file": "קובץ ערכת נושא",
|
||||
@@ -2015,6 +2371,16 @@
|
||||
"prefs.theme_follow_off": "כבוי",
|
||||
"prefs.theme_follow_stop": "הפסקת המעקב",
|
||||
"prefs.theme_import_hint": "לחצו כדי לבחור קובץ ערכת נושא, שחררו קובץ כאן, או הקישו Ctrl+V (Cmd+V ב-Mac) אחרי שהעתקתם ערכת נושא",
|
||||
"prefs.theme_option_opacity": "אטימות",
|
||||
"prefs.theme_option_opacity_help": "כוונון אטימות הלוחות הצפים. רמת אטימות מינימלית שומרת על קריאות הטקסט על רקע צבעי חלון התצוגה.",
|
||||
"prefs.theme_option_tab_colours": "צבעי כרטיסיות",
|
||||
"prefs.theme_option_tab_colours_help": "השתמש בצבעי הלוח ואזור התצוגה של ערכת נושא זו עבור כל כרטיסייה ברצועת הכלים.",
|
||||
"prefs.theme_option_tab_fade_ms": "מעבר בין כרטיסיות",
|
||||
"prefs.theme_option_tab_fade_ms_help": "שנה בהדרגה את צבעי הלוח ואזור התצוגה בעת מעבר בין כרטיסיות. ערך אפס מבצע את המעבר מיד.",
|
||||
"prefs.theme_options_badge": "אפשרויות",
|
||||
"prefs.theme_options_more": "עוד · {count}",
|
||||
"prefs.theme_options_reset": "איפוס",
|
||||
"prefs.theme_options_unavailable": "לא זמין במכשיר זה",
|
||||
"prefs.theme_paste": "הדבקת ערכת נושא",
|
||||
"prefs.theme_paste_none": "בלוח אין ערכת נושא של SolidCraft",
|
||||
"prefs.timeline_half_hour": "−30 דק׳",
|
||||
@@ -2036,13 +2402,23 @@
|
||||
"prefs.under_cursor": "מתחת לסמן",
|
||||
"prefs.units_precision": "יחידות ודיוק",
|
||||
"prefs.updates": "עדכונים",
|
||||
"prefs.value_boxes_in_view": "הצגת ערכים ליד הידיות שלהם בתצוגה",
|
||||
"prefs.value_boxes_in_view_tip": "ערך הפקודה (מרחק, רדיוס…) בתיבה ליד הידית שלו, מעל המודל. כבוי: מקלידים אותו בחלון הפקודה, שמקבל את המקלדת אחרי בחירה, ושום דבר לא מסתיר את המודל.",
|
||||
"prefs.view": "התנהגות המבט",
|
||||
"prefs.view_confirm_corner": "אישור וביטול בפינת התצוגה",
|
||||
"prefs.view_confirm_corner_note": "כשתיבת דו־שיח או סקיצה פתוחות, סימן וי וסימן איקס בפינה הימנית העליונה של התצוגה עושים את מה שעושים אישור וביטול של תיבת הדו־שיח, או מסיימים ומבטלים את הסקיצה. ניווט התצוגה זז אל מתחתיהם.",
|
||||
"prefs.viewport": "אזור התצוגה",
|
||||
"prefs.viewport_analysis_status": "הצגת מצב ניתוח בחלון התצוגה",
|
||||
"prefs.viewport_analysis_status_help": "הצגת ניתוחים פעילים מעל חלון התצוגה ופתיחת המקרא מכל פריט. Esc מכבה את הניתוח האחרון. כיבוי האפשרות משחזר את המקרא בפינה ואת פעולת Esc הקודמת.",
|
||||
"prefs.viewport_background": "רקע",
|
||||
"prefs.viewport_background_colour": "צבע",
|
||||
"prefs.viewport_background_theme": "מעבר הצבעים של ערכת הנושא",
|
||||
"prefs.viewport_section_status": "הצגת מצב חתך בחלון התצוגה",
|
||||
"prefs.viewport_section_status_help": "הצגת הגדרת החתך בחלון התצוגה. Escape ולחצן הסרט הפעיל מכבים את החתך. כיבוי האפשרות שומר על בקרי החתך הקודמים.",
|
||||
"prefs.viewport_status_details": "פרטים בזמן אמת בחלון התצוגה",
|
||||
"prefs.viewport_status_details_help": "עריכת הגדרות הניתוח והחתך הפעילים בכרטיסי פרטים אחידים. השבתה מחזירה את מקראי הניתוח לקריאה בלבד ואת תיבת הדו-שיח של חתך.",
|
||||
"prefs.viewport_status_summary": "סיכום פריטי מצב בחלון התצוגה",
|
||||
"prefs.viewport_status_summary_help": "קיבוץ שלושה פריטי מצב או יותר לתג סיכום אחד. כיבוי האפשרות משאיר כל פריט בשורה המלאה.",
|
||||
"prefs.wheel": "גלגלת",
|
||||
"prefs.wheel_trackpad": "גלגלת ומשטח מגע",
|
||||
"prefs.workspace": "סביבת עבודה",
|
||||
@@ -2052,6 +2428,10 @@
|
||||
"properties.title": "מאפיינים: {name}",
|
||||
"recovery.days_ago": "לפני {count} ימים",
|
||||
"recovery.detail": "{file} · {features} פיצ'רים · נשמר אוטומטית {when}",
|
||||
"recovery.discard_all": "השלכת הכול",
|
||||
"recovery.discard_all_detail": "לא ניתן לבטל פעולה זו.",
|
||||
"recovery.discard_all_title": "להשליך {count} שמירות אוטומטיות?",
|
||||
"recovery.discard_all_title_one": "להשליך שמירה אוטומטית אחת?",
|
||||
"recovery.hours_ago": "לפני {count} שע'",
|
||||
"recovery.just_now": "זה עתה",
|
||||
"recovery.min_ago": "לפני {count} דק'",
|
||||
@@ -2917,7 +3297,9 @@
|
||||
"render.output_ready": "מוכן לרינדור",
|
||||
"render.output_run_check": "הפעל בדיקה",
|
||||
"render.output_size_limit": "{method}: עד {dimension} פיקסלים לצלע ו-{pixels} פיקסלים. הגודל הגדול ביותר שמתאים: {width} × {height}.",
|
||||
"render.output_size_method_profile": "כדי לרנדר {width} × {height}, יש לבחור ב-{method} עם פרופיל משאבי CPU {profile} או בגודל קטן יותר.",
|
||||
"render.output_size_ok": "הגודל תקין · {width} × {height} פיקסלים",
|
||||
"render.output_size_profile": "כדי לרנדר {width} × {height}, יש לבחור בפרופיל משאבי CPU {profile} או בגודל קטן יותר.",
|
||||
"render.output_swap_orientation": "החלפת רוחב וגובה",
|
||||
"render.output_tools_inspector": "ערוך גודל ופורמט במפקח הפלט.",
|
||||
"render.output_view_image": "הצג תמונה",
|
||||
@@ -3130,6 +3512,7 @@
|
||||
"render.size_custom": "מותאם…",
|
||||
"render.size_full_hd": "Full HD",
|
||||
"render.size_hd": "HD",
|
||||
"render.size_needs_profile": "{size} · נדרש {profile}",
|
||||
"render.size_presets": "הגדרות גודל מוכנות",
|
||||
"render.size_presets_pending": "יגיע עם עורך הפלט",
|
||||
"render.size_preview": "תצוגה מקדימה",
|
||||
@@ -3417,6 +3800,24 @@
|
||||
"sheet.flange_type_contour": "מתאר",
|
||||
"sheet.flange_type_edge": "מקצוע",
|
||||
"sheet.no_body": "אין גוף פח: יש להתחיל אחד עם אוגן > בסיס, או להמיר לוח לפח עם המרה לפח (יש לבחור את הפאה השטוחה הגדולה שלו)",
|
||||
"sheet.personal_rules.confirm_delete": "אישור מחיקה",
|
||||
"sheet.personal_rules.delete": "מחיקה",
|
||||
"sheet.personal_rules.delete_prompt": "למחוק את הכלל האישי הזה? כללים שכבר נמצאים בתכנים לא ישתנו.",
|
||||
"sheet.personal_rules.full": "הספרייה האישית כבר מכילה 64 כללים.",
|
||||
"sheet.personal_rules.invalid_name": "יש להזין שם קצר ללא מעברי שורה או תווי בקרה.",
|
||||
"sheet.personal_rules.invalid_values": "יש להשלים את ערכי הכלל: כל ערך צריך להיות ניתן לחישוב בתכן זה, עם עובי חיובי ומקדם K בין 0 ל־1.",
|
||||
"sheet.personal_rules.missing": "הכלל האישי שנבחר כבר אינו זמין.",
|
||||
"sheet.personal_rules.name": "שם הכלל",
|
||||
"sheet.personal_rules.name_exists": "כבר קיים כלל אישי בשם הזה. יש להשתמש בשם אחר.",
|
||||
"sheet.personal_rules.name_hint": "שם ייחודי",
|
||||
"sheet.personal_rules.overwrite": "שמירת השינויים בכלל האישי שנבחר",
|
||||
"sheet.personal_rules.rename": "שינוי שם",
|
||||
"sheet.personal_rules.rule": "כלל אישי",
|
||||
"sheet.personal_rules.save": "שמירה כחדש",
|
||||
"sheet.personal_rules.scope": "נשמרים בפרופיל שלך לכל התכנים.",
|
||||
"sheet.personal_rules.select": "בחירת כלל",
|
||||
"sheet.personal_rules.title": "כללים אישיים",
|
||||
"sheet.personal_rules.unsupported": "לכלל הזה יש ערכים שהגרסה הזו אינה יכולה להשתמש בהם.",
|
||||
"shortcut.json_error": "הפרמטרים חייבים להיות JSON: {error}",
|
||||
"shortcut.no_command": "אין פקודה `{id}`; הטקסט שלפני ה־JSON חייב להיות מזהה פקודה",
|
||||
"shortcut.pin": "הצמדה לראש תיבת S",
|
||||
@@ -3453,8 +3854,10 @@
|
||||
"sketch_text.align_right": "ימין",
|
||||
"sketch_text.bold": "מודגש",
|
||||
"sketch_text.builtin_font": "{family} (מובנה)",
|
||||
"sketch_text.formula": "התחילו ב־= כדי לבנות את הטקסט מפרמטרים: ='W' + number(Width)",
|
||||
"sketch_text.italic": "נטוי",
|
||||
"sketch_text.loading_fonts": "מחפש גופנים מותקנים…",
|
||||
"sketch_text.no_bold": "לגופן המובנה אין משקל מודגש: בחר גופן מותקן",
|
||||
"sketch_text.on_path": "הטקסט עוקב אחר המסלול שלו: העקומה קובעת את מיקומו",
|
||||
"sketch_text.path_clear": "הסרת הטקסט מהעקומה",
|
||||
"sketch_text.path_hint": "עקומה בסקיצה שהטקסט עוקב אחריה: יש ללחוץ כאן ואז על העקומה",
|
||||
@@ -3593,6 +3996,8 @@
|
||||
"ui.3d_mouse_section": "עכבר תלת־ממדי",
|
||||
"ui.3d_mouse_show_in_view": "הצגת העכבר התלת־ממדי בתצוגה התלת־ממדית",
|
||||
"ui.3d_mouse_show_in_view_tip": "תמונה של העכבר התלת־ממדי בפינה השמאלית התחתונה, שזזה כשמזיזים אותו.",
|
||||
"ui.3d_mouse_sketch_orbit": "סיבוב סקיצות בעכבר התלת־ממדי",
|
||||
"ui.3d_mouse_sketch_orbit_tip": "העכבר התלת־ממדי מסובב את התצוגה גם כשסקיצה פתוחה ונראית חזיתית, כמו שהעכבר יכול. כבוי: הוא מזיז ומגדיל את הסקיצה עד שתטה את התצוגה.",
|
||||
"ui.3d_mouse_skip": "ההתקן שלי לא יכול לעשות את זה",
|
||||
"ui.3d_mouse_skip_tip": "מדלג על התנועה הזאת בשני הכיוונים, והכיול משמיט אותה.",
|
||||
"ui.3d_mouse_speed": "מהירות עכבר תלת־ממדי",
|
||||
@@ -3621,6 +4026,8 @@
|
||||
"ui.3d_mouse_step_twist_counterclockwise": "יש לסובב את הכיפה נגד כיוון השעון, להחזיק ואז לשחרר.",
|
||||
"ui.3d_mouse_switch_cap": "כיול כהתקן חזרה למרכז",
|
||||
"ui.3d_mouse_switch_trackball": "כיול ככדור עקיבה",
|
||||
"ui.3d_mouse_use_direct": "שימוש במנהל ישיר",
|
||||
"ui.3d_mouse_use_direct_tip": "קריאת העכבר התלת־ממדי ישירות (hidraw) במקום דרך spacenavd.",
|
||||
"ui.3d_mouse_view_axis": "ציר מבט",
|
||||
"ui.3d_mouse_view_off": "כבוי",
|
||||
"ui.3d_mouse_view_off_tip": "הפרופיל של מנהל ההתקן לעכבר התלת־ממדי מכבה את הציר הזה, ולכן התנועה שלו לא מזיזה את המבט. בחירה כאן בתנועה של ציר אחר מחליפה בין השניים, והתנועה ההיא מפסיקה להזיז את המבט.",
|
||||
@@ -3659,6 +4066,7 @@
|
||||
"ui.agent_chat_auth_terminal": "יש להריץ את זה במסוף ואז ללחוץ שוב על התחברות:",
|
||||
"ui.agent_chat_auth_title": "התחברות לסוכן",
|
||||
"ui.agent_chat_cancel": "ביטול",
|
||||
"ui.agent_chat_cannot_start": "מותקן, אך אינו מופעל: {error}",
|
||||
"ui.agent_chat_changes": "שינויים: {n}, צעד ביטול אחד",
|
||||
"ui.agent_chat_changes_n": "{n} שינויים",
|
||||
"ui.agent_chat_changes_of": "{n}/{limit} שינויים",
|
||||
@@ -3751,9 +4159,12 @@
|
||||
"ui.agent_chat_queued_stopped": "בתור (נעצר, לא נשלח)",
|
||||
"ui.agent_chat_refresh": "רענון",
|
||||
"ui.agent_chat_refused": "אסור לסוכן: {reason}",
|
||||
"ui.agent_chat_reinstall": "{agent} מותקן ({program}), אך לא הופעל כאשר SolidCraft בדק אותו: {error}\nייתכן שההתקנה שלו חלקית, או שהיא מיועדת לסוג אחר של מחשב. יש להתקין אותו מחדש עם `{install}`, לוודא שהוא מציג את הגרסה שלו במסוף, ואז ללחוץ על רענון.",
|
||||
"ui.agent_chat_remove": "הסרה מהתור",
|
||||
"ui.agent_chat_remove_file": "הסרה מההודעה הזו",
|
||||
"ui.agent_chat_remove_imported": "הסרה מההודעה הזו; החלק נשאר בתכן (ביטול מסיר אותו)",
|
||||
"ui.agent_chat_reply_cut_off": "התשובה הגיעה למגבלת האורך שלה לפני שהסתיימה, ולכן ייתכן שהיא חלקית. יש לבקש מהסוכן להמשיך, או לענות בקצרה יותר.",
|
||||
"ui.agent_chat_reply_declined": "המודל סירב לענות על ההודעה הזו.",
|
||||
"ui.agent_chat_retry": "ניסיון חוזר",
|
||||
"ui.agent_chat_right": "ימין",
|
||||
"ui.agent_chat_save": "שמירה",
|
||||
@@ -3812,12 +4223,17 @@
|
||||
"ui.ai_copy_suffix": "עותק",
|
||||
"ui.ai_custom_url": "URL מותאם אישית",
|
||||
"ui.ai_default": "ברירת מחדל",
|
||||
"ui.ai_edit": "עריכה",
|
||||
"ui.ai_edit_agent_title": "עריכת סוכן",
|
||||
"ui.ai_edit_gone": "הסוכן הזה הוסר, ולכן אין מה לשמור.",
|
||||
"ui.ai_edit_tip": "שינוי השם, הפקודה או נקודת הקצה של סוכן זה. מפתח שמור נשאר מוסתר.",
|
||||
"ui.ai_http_busy": "נקודת הקצה עמוסה או חרגה מהמגבלה שלה; יש לנסות שוב מאוחר יותר",
|
||||
"ui.ai_http_key": "נקודת הקצה דחתה את המפתח: יש לבדוק אותו בהעדפות > AI",
|
||||
"ui.ai_http_not_found": "נקודת הקצה או המודל לא קיימים: יש לבדוק את URL הבסיס ואת שם המודל",
|
||||
"ui.ai_http_too_large": "השיחה גדולה מדי עבור נקודת קצה זו; יש להתחיל צ'אט חדש",
|
||||
"ui.ai_key": "מפתח API",
|
||||
"ui.ai_key_hint": "רשות; נשמר במחזיק המפתחות של המערכת",
|
||||
"ui.ai_key_keep_hint": "יש להשאיר ריק כדי לשמור על המפתח השמור",
|
||||
"ui.ai_key_needs_https": "מפתח נשלח רק דרך HTTPS, או למחשב הזה.",
|
||||
"ui.ai_key_note": "נשמר במחזיק המפתחות של המערכת, לעולם לא בהגדרות של SolidCraft. יש להשאיר ריק עבור שרת מקומי.",
|
||||
"ui.ai_keychain_error": "מחזיק המפתחות של המערכת סירב: {error}",
|
||||
@@ -3844,11 +4260,15 @@
|
||||
"ui.ai_permissions": "הרשאות",
|
||||
"ui.ai_preset": "תצורה מוכנה",
|
||||
"ui.ai_protocol": "פרוטוקול",
|
||||
"ui.ai_reasoning_effort": "מאמץ ההסקה",
|
||||
"ui.ai_reasoning_effort_field_hint": "ריק = ברירת המחדל של הספק",
|
||||
"ui.ai_reasoning_effort_hint": "אופציונלי. נשלח לנקודת הקצה כ־`reasoning_effort`; הערכים המקובלים שונים מספק לספק (למשל `low`, `high` או `max`). SolidCraft לעולם לא תחליף את הערך שבחרת כאן. השאירו ריק כדי לא לשלוח דבר ולשמור על ברירת המחדל של הספק.",
|
||||
"ui.ai_remove": "הסרה",
|
||||
"ui.ai_request_timed_out": "המודל נזקק ליותר מ־{seconds} שניות. ניתן להגדיל את זמן ההמתנה לבקשה עבור נקודת קצה זו בהעדפות › עוזר.",
|
||||
"ui.ai_request_timeout": "זמן המתנה לבקשה",
|
||||
"ui.ai_request_timeout_hint": "כמה זמן מותר לבקשה אחת למודל בנקודת קצה זו, מ־30 שניות עד שעה. כדאי להגדיל עבור מודל מקומי איטי.",
|
||||
"ui.ai_reset": "איפוס",
|
||||
"ui.ai_save": "שמירה",
|
||||
"ui.ai_settings": "הגדרות AI…",
|
||||
"ui.ai_show_features": "הצגת תכונות AI",
|
||||
"ui.ai_show_features_note": "הצ'אט עם הסוכן: חלונית שבה סוכן קוד שכבר נמצא בשימוש, או נקודת קצה של מודל לבחירתך, עובדים על התכן הפתוח. כבוי: אין לחצן AI, קיצור דרך, פריט תפריט או חלונית, ושום דבר לא מחופש או מופעל.",
|
||||
@@ -3937,6 +4357,7 @@
|
||||
"ui.circle": "מעגל",
|
||||
"ui.circular_pattern": "מערך מעגלי",
|
||||
"ui.clear": "ניקוי",
|
||||
"ui.clear_print_face": "נקה פאת הדפסה",
|
||||
"ui.clear_recent": "ניקוי האחרונים",
|
||||
"ui.clear_the_selection": "ניקוי הבחירה",
|
||||
"ui.click_selects_whole_bodies": "לחיצה בוחרת גופים שלמים",
|
||||
@@ -3971,6 +4392,15 @@
|
||||
"ui.constant": "קבוע",
|
||||
"ui.constraints_conflict": "התנגשות בין אילוצים",
|
||||
"ui.construction": "עזר",
|
||||
"ui.construction.angle_hint": "ישר עזר: בחירת נקודה ואז הקלדת זווית או בחירת כיוון",
|
||||
"ui.construction.bisector_hint": "חוצה זווית: בחירת שני ישרים נחתכים ואז הפתרון הרצוי",
|
||||
"ui.construction.common_hint": "משיק משותף: בחירת שני מעגלים/קשתות ואז הפתרון הרצוי",
|
||||
"ui.construction.contact_hint": "משיק: בחירת מעגל/קשת או ספליין/חתך חרוט פתוח ואז נקודת השקה (לעקומות חופשיות: קצוות בלבד)",
|
||||
"ui.construction.external_hint": "משיק: בחירת מעגל או קשת, נקודה חיצונית ואז הפתרון הרצוי",
|
||||
"ui.construction.free_hint": "ישר עזר: לחיצה על שתי נקודות; לחיצה ימנית להתחלה מחדש",
|
||||
"ui.construction.point_hint": "ישר עזר: לחיצה על נקודת המעבר",
|
||||
"ui.construction.reference_hint": "ישר עזר: בחירת ישר ואז נקודה; לחיצה ימנית להחלפת הייחוס",
|
||||
"ui.construction.ribbon_label": "קווי עזר",
|
||||
"ui.context_menu": "תפריט הקשר",
|
||||
"ui.continuity_g0": "G0 שבר",
|
||||
"ui.continuity_g1": "G1 משיק",
|
||||
@@ -3998,6 +4428,7 @@
|
||||
"ui.dark": "כהה",
|
||||
"ui.default_modelling_orientation": "כיוון מידול ברירת מחדל",
|
||||
"ui.delete": "מחיקה",
|
||||
"ui.delete_select_first": "בחרו קודם מה למחוק: תכונות, גופים, רכיבים או גאומטריית סקיצה",
|
||||
"ui.depth": "עומק",
|
||||
"ui.design": "תכן",
|
||||
"ui.design_properties.author": "מחבר",
|
||||
@@ -4012,6 +4443,40 @@
|
||||
"ui.design_properties.project": "פרויקט",
|
||||
"ui.design_properties.revision": "גרסה",
|
||||
"ui.design_saved": "נשמר ב־{path}",
|
||||
"ui.details_access_caption": "הפאות מציגות אם כלי יכול להגיע אליהן מהכיוון שנבחר.",
|
||||
"ui.details_angle": "זווית",
|
||||
"ui.details_continuity_caption": "עריכת התפר שנבחר. שאר התפרים שומרים על ההגדרות שלהם.",
|
||||
"ui.details_continuity_stale": "גאומטריה קודמת: יש להריץ שוב את הניתוח כדי לערוך את התפר הזה או להתאים את התצוגה אליו.",
|
||||
"ui.details_copy_list": "העתקת הרשימה",
|
||||
"ui.details_curvature": "סבולת עקמומיות",
|
||||
"ui.details_curvature_caption": "הפאות נצבעות לפי רדיוס העקמומיות המקומי שלהן.",
|
||||
"ui.details_direction": "כיוון הכלי",
|
||||
"ui.details_draft_caption": "הפאות נצבעות לפי הזווית שלהן ביחס לכיוון החליצה.",
|
||||
"ui.details_edit_seam": "עריכת תפר",
|
||||
"ui.details_fixture": "דוגמת רכיב ממשק — נתוני דוגמה בלבד",
|
||||
"ui.details_fixture_caption": "דוגמת רכיב ממשק עם ערכים להמחשה; זו אינה תוצאה של מודל.",
|
||||
"ui.details_fixture_problem": "ממצא לדוגמה עם בעיה",
|
||||
"ui.details_fixture_readout": "ערך מדידה לדוגמה",
|
||||
"ui.details_flip": "היפוך",
|
||||
"ui.details_gap": "פער",
|
||||
"ui.details_hatch": "קיווקוו פאות החתך",
|
||||
"ui.details_jump": "קפיצת עקמומיות",
|
||||
"ui.details_key": "מקרא",
|
||||
"ui.details_offset": "היסט",
|
||||
"ui.details_plane": "מישור",
|
||||
"ui.details_pull": "כיוון החליצה",
|
||||
"ui.details_radius": "רדיוס",
|
||||
"ui.details_readout": "ערכים נמדדים",
|
||||
"ui.details_samples": "דגימות",
|
||||
"ui.details_seam": "{body} · מקצוע {edge}",
|
||||
"ui.details_settings": "הגדרות",
|
||||
"ui.details_sharp_gap": "חד או בעל פער",
|
||||
"ui.details_show_all": "הצגת הכול ({count})",
|
||||
"ui.details_smooth": "חלק",
|
||||
"ui.details_stripes": "פסים",
|
||||
"ui.details_target": "התאמת התצוגה לגאומטריה",
|
||||
"ui.details_worst_seams": "התפרים הגרועים ביותר",
|
||||
"ui.details_zebra_caption": "פסי ההשתקפות מראים באיזו מידה הפאות מתחברות בצורה חלקה.",
|
||||
"ui.diameter": "קוטר",
|
||||
"ui.dimension": "מידה",
|
||||
"ui.direct_interaction": "אינטראקציה ישירה",
|
||||
@@ -4056,6 +4521,7 @@
|
||||
"ui.edit_in_place_saved_elsewhere": "החלק נשמר לקובץ אחר; ההרכבה עדיין מקושרת אל {name}",
|
||||
"ui.edit_in_place_wait": "יש להמתין עד שמה שפועל בתכן יסתיים",
|
||||
"ui.edit_section_analysis": "עריכת ניתוח חתך",
|
||||
"ui.edit_sketch_empty": "אין סקיצות לעריכה",
|
||||
"ui.ellipse": "אליפסה",
|
||||
"ui.emboss_wrap_note": "פרופילי קווים ניצבים המשיקים לגליל נתמך נכרכים אוטומטית. יש לבחור דופן כדי לקבוע יעד.",
|
||||
"ui.end_radius": "רדיוס סיום",
|
||||
@@ -4066,12 +4532,15 @@
|
||||
"ui.equation_explicit": "מפורשת",
|
||||
"ui.equation_form": "צורה",
|
||||
"ui.equation_note": "המשתנה הוא מספר ללא יחידה: sin(t) מקבלת אותו ברדיאנים. תוצאה ללא יחידה היא ביחידה של התכנון.",
|
||||
"ui.equation_note_range": "המשתנה הוא אורך, כמו הטווח שלו: אפשר לשלב אותו עם פרמטרי אורך, ולחלק אותו באורך עבור sin(). תוצאה ללא יחידה היא ביחידת התכן.",
|
||||
"ui.equation_parametric": "פרמטרית",
|
||||
"ui.equation_variable_unit": "המשתנה ביחידת הטווח",
|
||||
"ui.equation_x_of_t": "x(t)",
|
||||
"ui.equation_y_of_t": "y(t)",
|
||||
"ui.equation_y_of_x": "y(x)",
|
||||
"ui.equivalent_radius": "רדיוס שקול",
|
||||
"ui.expand": "הרחבה",
|
||||
"ui.explode_needs_two_components": "תצוגה מפוצצת מרחיקה רכיבים זה מזה, ולכן התכן צריך שניים או יותר מהם (רכיב חדש, הוספת תכן או יצירת רכיבים מגופים)",
|
||||
"ui.exportDxf": "ייצוא DXF…",
|
||||
"ui.export_ellipsis_keymap": "ייצוא…",
|
||||
"ui.export_keymap_tip": "מקשים, מועדפי תיבת S וסרגל הכלים, כקובץ",
|
||||
@@ -4240,12 +4709,14 @@
|
||||
"ui.joints": "מפרקים",
|
||||
"ui.keyboard_shortcuts": "קיצורי מקלדת",
|
||||
"ui.language": "שפה",
|
||||
"ui.lasso_select": "לאסו (גרירת לולאה חופשית: בוחר את מה שנמצא כולו בתוכה)",
|
||||
"ui.layout_compact": "דחוס",
|
||||
"ui.layout_floating": "צף",
|
||||
"ui.length": "אורך",
|
||||
"ui.length_decimals": "ספרות עשרוניות באורך",
|
||||
"ui.light": "בהיר",
|
||||
"ui.line": "קו",
|
||||
"ui.line_arc_hint": "קשת משיקה: לחצו על קצה הקשת. השהו שוב על הנקודה האחרונה כדי לחזור לקווים; לחיצה ימנית או Esc לסיום",
|
||||
"ui.link_copies": "קישור עותקים זהים",
|
||||
"ui.link_copies_keep": "השארה",
|
||||
"ui.link_copies_link": "קישור",
|
||||
@@ -4334,6 +4805,7 @@
|
||||
"ui.part_size_shared": "בונה מחדש את החלק ומחליף פיצ'רים שנוספו. כל המופעים של רכיב זה מתעדכנים.",
|
||||
"ui.paste": "הדבקה",
|
||||
"ui.path": "מסלול",
|
||||
"ui.pattern_object_type_tip": "גופים: צורות מלאות, נבחרות בתצוגה או בעץ התכן; כל אחד מועתק בשלמותו.\nפיצ'רים: שלבים בציר הזמן, כמו שליפה או חור, נבחרים בציר הזמן או על פאה שהם יצרו; השלב חוזר על עצמו.\nסקיצה אינה אף אחד מהם: חזרו על העקומות שלה בעזרת המערך או השיקוף של הסקיצה עצמה, או בצעו לה שליפה קודם.",
|
||||
"ui.pattern_on_path": "מערך לאורך מסלול",
|
||||
"ui.perforate_margin_default": "לפי הקוטר",
|
||||
"ui.perforate_pitch": "פסיעה",
|
||||
@@ -4360,12 +4832,17 @@
|
||||
"ui.plugins_skipped": "לא ניתן היה לקרוא {count} תיקיות.",
|
||||
"ui.plugins_version": "{version}",
|
||||
"ui.point": "נקודה",
|
||||
"ui.point_cloud_add_filter": "הוספת מסנן…",
|
||||
"ui.point_cloud_auto_range": "טווח אוטומטי",
|
||||
"ui.point_cloud_color_by": "צביעה לפי",
|
||||
"ui.point_cloud_file_colors": "צבעי הקובץ",
|
||||
"ui.point_cloud_filter_by": "סינון לפי",
|
||||
"ui.point_cloud_height_high": "הגובה המרבי",
|
||||
"ui.point_cloud_height_low": "הגובה המזערי",
|
||||
"ui.point_cloud_legend_filter": "מוצגים ומוסתרים במקרא שלמעלה",
|
||||
"ui.point_cloud_no_file_colors": "אין בקובץ צבעים",
|
||||
"ui.point_cloud_pause": "השהיה",
|
||||
"ui.point_cloud_play": "הפעלה",
|
||||
"ui.point_cloud_single_color": "צבע אחיד",
|
||||
"ui.point_cloud_size": "גודל נקודה",
|
||||
"ui.point_cloud_units": "יחידות הקובץ",
|
||||
@@ -4374,6 +4851,11 @@
|
||||
"ui.polygon": "מצולע",
|
||||
"ui.preferences": "העדפות",
|
||||
"ui.press_a_key": "יש ללחוץ על מקש…",
|
||||
"ui.print_face_cleared": "{body}: פאת ההדפסה נוקתה",
|
||||
"ui.print_face_input": "פאת הדפסה",
|
||||
"ui.print_face_one_body": "פאת הדפסה נבחרת לגוף אחד: שלח את הגוף הזה לבדו כדי לשנות אותה",
|
||||
"ui.print_face_pick": "בחר פאה שטוחה אחת של גוף מוצק כדי להפוך אותה לפאת ההדפסה",
|
||||
"ui.print_face_set": "{body}: פאת ההדפסה הוגדרה; שליחה לסלייסר מניחה את הגוף עליה",
|
||||
"ui.profile": "פרופיל",
|
||||
"ui.profile_plane": "מישור הפרופיל",
|
||||
"ui.profiles": "פרופילים",
|
||||
@@ -4389,6 +4871,7 @@
|
||||
"ui.properties.inertia_y": "Iyx, Iyy, Iyz",
|
||||
"ui.properties.inertia_z": "Izx, Izy, Izz",
|
||||
"ui.properties.measuring": "מודד…",
|
||||
"ui.properties.measuring_bodies": "מודד… {done} מתוך {total} גופים",
|
||||
"ui.properties.measuring_failed": "המדידה נעצרה לפני שהסתיימה.",
|
||||
"ui.properties.principal_axis": "ציר ראשי {number}",
|
||||
"ui.properties.principal_moments": "מומנטים ראשיים",
|
||||
@@ -4437,6 +4920,7 @@
|
||||
"ui.revolve": "סיבוב",
|
||||
"ui.ribbon_exit": "יציאה",
|
||||
"ui.ribbon_labels": "הצגת טקסט מתחת לסמלי רצועת הכלים",
|
||||
"ui.ribbon_menus_skip_pinned": "השמטת פקודות מוצמדות מהתפריטים הנפתחים",
|
||||
"ui.ribbon_pin_footer": "פקודות מוצמדות מוצגות ברצועת הכלים. יש לרחף מעל שורה כדי להצמיד אותה או לבטל את הצמדתה.",
|
||||
"ui.ribbon_workspace": "סביבת עבודה",
|
||||
"ui.right": "ימין",
|
||||
@@ -4455,6 +4939,7 @@
|
||||
"ui.selectOther": "בחירת אחר…",
|
||||
"ui.selectTangentChain": "בחירת שרשרת משיקה",
|
||||
"ui.select_all": "בחירת הכול",
|
||||
"ui.select_components_by_face": "בחירת רכיבים (בחירת פאה בוחרת את הרכיב שלה)",
|
||||
"ui.selection": "בחירה",
|
||||
"ui.selection_modifiers": "מקשי שינוי לבחירה",
|
||||
"ui.selection_shift_add_only": "Shift+לחיצה מוסיף בלי להסיר",
|
||||
@@ -4496,6 +4981,11 @@
|
||||
"ui.sketch_intersect_selection_filter": "מסנן בחירה",
|
||||
"ui.sketch_modifiers": "מקשי שינוי בסקיצה",
|
||||
"ui.sketch_project_geometry": "גאומטריה",
|
||||
"ui.sketch_report.all_constrained": "הכול מאולץ במלואו.",
|
||||
"ui.sketch_report.dof": "דרגות חופש",
|
||||
"ui.sketch_report.loose": "לא מאולץ במלואו",
|
||||
"ui.sketch_report.status": "מצב",
|
||||
"ui.sketch_report.title": "דוח סקיצה",
|
||||
"ui.sketch_scale": "קנה מידה של סקיצה",
|
||||
"ui.sketches": "סקיצות",
|
||||
"ui.slice": "חתך",
|
||||
@@ -4600,10 +5090,19 @@
|
||||
"ui.view_centre": "מרכז המבט",
|
||||
"ui.viewport_status_clear": "כיבוי {name}",
|
||||
"ui.viewport_status_clear_hint": "כיבוי {name} · Esc",
|
||||
"ui.viewport_status_edges": "{count} קצוות",
|
||||
"ui.viewport_status_from": "מכיוון {direction}",
|
||||
"ui.viewport_status_key": "הצגת מקרא עבור {name}",
|
||||
"ui.viewport_status_minimum_radius": "רדיוס מינימלי",
|
||||
"ui.viewport_status_pairs": "{count} זוגות",
|
||||
"ui.viewport_status_section_hatch": "{setting} · קווקוו",
|
||||
"ui.viewport_status_section_plane": "המישור הנוכחי",
|
||||
"ui.viewport_status_section_tilted": "נטוי · {offset}",
|
||||
"ui.viewport_status_stripes": "{count} פסים",
|
||||
"ui.viewport_status_summary_clear": "כיבוי הכול",
|
||||
"ui.viewport_status_summary_heading": "בתצוגה זו",
|
||||
"ui.viewport_status_summary_label": "{name} ועוד {count} פריטים",
|
||||
"ui.viewport_status_summary_more": "+{count}",
|
||||
"ui.viewport_theme_follow": "לפי ערכת הנושא",
|
||||
"ui.visual_shaded_hidden_edges": "מוצלל עם מקצועות נסתרים",
|
||||
"ui.visual_shaded_with_edges": "מוצלל עם מקצועות",
|
||||
@@ -4640,7 +5139,9 @@
|
||||
"update.button": "עדכון",
|
||||
"update.button_version": "עדכון ל־{version}",
|
||||
"update.check_automatically": "בדיקת עדכונים אוטומטית",
|
||||
"update.check_for_updates": "בדיקת עדכונים",
|
||||
"update.check_now": "בדיקה עכשיו",
|
||||
"update.check_unavailable": "בדיקת עדכונים אינה זמינה עבור התקנה זו.",
|
||||
"update.checking": "בבדיקה…",
|
||||
"update.copy": "העתקה",
|
||||
"update.dmg_opened": "תמונת הדיסק פתוחה ואומתה: יש לגרור את SolidCraft לתיקיית היישומים במקום העותק הישן, ואז להפעיל מחדש את SolidCraft.",
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
"BLEND SURFACE": "ブレンドサーフェス",
|
||||
"BOUNDARY SURFACE": "境界サーフェス",
|
||||
"BROWSER": "ブラウザ",
|
||||
"Back to the original order": "元の順序に戻す",
|
||||
"Ball": "ボール",
|
||||
"Bar": "平鋼",
|
||||
"Base Center": "底面の中心",
|
||||
@@ -595,6 +596,8 @@
|
||||
"Snap to face and edge centres": "面とエッジの中心にスナップ",
|
||||
"SolidCraft cannot submit reports directly. Submit on GitHub; no token is needed in the app.": "SolidCraftからレポートを直接送信することはできません。GitHubで送信してください。アプリにトークンは必要ありません。",
|
||||
"SolidCraft closed before these designs were saved. Their last autosave can be opened.": "これらのデザインが保存される前にSolidCraftが終了しました。最後の自動保存ファイルを開くことができます。",
|
||||
"Sort A to Z": "昇順で並べ替え",
|
||||
"Sort Z to A": "降順で並べ替え",
|
||||
"Spacing 2 must be a non-zero number": "間隔 2は0以外の数値にしてください",
|
||||
"Spacing must be a non-zero number": "間隔は0以外の数値にしてください",
|
||||
"Specialise": "特殊操作",
|
||||
@@ -775,6 +778,8 @@
|
||||
"at the face": "面の位置",
|
||||
"bom.group_children": "サブパーツを親パーツの行に含める",
|
||||
"browser.body_name": "ボディ{number}",
|
||||
"browser.calibrate_click_a": "画像をクリックして点Aを指定するか、座標を入力してください。",
|
||||
"browser.calibrate_click_b": "画像をクリックして点Bを指定するか、座標を入力してください。",
|
||||
"browser.calibrate_title": "尺度を設定: {name}",
|
||||
"browser.capture_many": "{count}個のコンポーネントが移動されましたが、位置がキャプチャされていません。",
|
||||
"browser.capture_note": "「位置をキャプチャ」で新しい位置を保持し、「位置を元に戻す」で以前の位置に戻します。",
|
||||
@@ -817,6 +822,8 @@
|
||||
"cmd.appearance_pick_up": "外観を取得",
|
||||
"cmd.appearance_replace": "外観を置換",
|
||||
"cmd.assembly_bom": "部品表",
|
||||
"cmd.assembly_mass_properties": "質量特性",
|
||||
"cmd.body.print_face": "造形面",
|
||||
"cmd.body_rename": "ボディの名前を変更",
|
||||
"cmd.browser_collapse_all": "すべて折りたたむ",
|
||||
"cmd.browser_expand_all": "すべて展開",
|
||||
@@ -1101,6 +1108,16 @@
|
||||
"cmd.sheet_refold": "折り戻し",
|
||||
"cmd.sheet_rules": "板金ルールを一覧表示",
|
||||
"cmd.sheet_unfold": "展開",
|
||||
"cmd.sketch.construction_line": "補助直線",
|
||||
"cmd.sketch.construction_line.angle": "角度指定の補助直線",
|
||||
"cmd.sketch.construction_line.bisector": "角の二等分線",
|
||||
"cmd.sketch.construction_line.horizontal": "水平補助直線",
|
||||
"cmd.sketch.construction_line.parallel": "平行補助直線",
|
||||
"cmd.sketch.construction_line.perpendicular": "直交補助直線",
|
||||
"cmd.sketch.construction_line.tangent_at": "曲線上の点での接線",
|
||||
"cmd.sketch.construction_line.tangent_external": "外部点を通る接線",
|
||||
"cmd.sketch.construction_line.tangent_two": "共通接線",
|
||||
"cmd.sketch.construction_line.vertical": "垂直補助直線",
|
||||
"cmd.sketch_arc3d": "3D 円弧",
|
||||
"cmd.sketch_arc_center_point": "中心点円弧",
|
||||
"cmd.sketch_arc_tangent": "正接円弧",
|
||||
@@ -1231,6 +1248,7 @@
|
||||
"cmd.view.render_browser": "Renderブラウザー",
|
||||
"cmd.view.render_dock": "レンダードックを移動",
|
||||
"cmd.view.render_focus": "Renderフォーカス表示",
|
||||
"cmd.view.status_details": "ビューポートの状態の詳細",
|
||||
"cmd.view.status_items": "ビューポートの状態項目",
|
||||
"cmd.view_ambient_occlusion": "アンビエントオクルージョン",
|
||||
"cmd.view_angle_readout": "ビュー角度",
|
||||
@@ -1269,8 +1287,14 @@
|
||||
"color.hex_hint": "#rrggbb",
|
||||
"color.hue": "色相",
|
||||
"color.linear": "0〜1の線形空間で色の値を表示",
|
||||
"color.recent": "最近使った色",
|
||||
"color.recent_help": "どの色フィールドで選んだ色もここに表示されます",
|
||||
"color.saturation": "彩度(パーセント)",
|
||||
"color.saturation_value": "彩度と明度",
|
||||
"color.selected": "選択した色",
|
||||
"color.step_down": "1 ステップ下げる",
|
||||
"color.step_up": "1 ステップ上げる",
|
||||
"color.value": "明度(パーセント)",
|
||||
"config.column_filter_empty": "一致する列がありません",
|
||||
"contact.components_count": "{count}個のコンポーネント",
|
||||
"contact.enabled_label": "有効",
|
||||
@@ -1317,6 +1341,7 @@
|
||||
"dialog.dimension_name": "寸法: {name}",
|
||||
"dialog.edit_title": "{title}を編集",
|
||||
"dialog.no_shown_body": "変更できる表示中のボディがありません。ボディを表示するか、新規ボディを選択してください",
|
||||
"dialog.pattern_sketch_not_object": "ボディかフィーチャーを選んでください。スケッチはどちらでもありません。曲線はスケッチ内のパターンかミラーで繰り返すか、先に押し出してください。",
|
||||
"dialog.select": "↖ 選択",
|
||||
"dialog.selected_count": "↖ {count} 個選択中",
|
||||
"dialog.selection_guidance": "入力欄を選んで変更します。選択済みのオブジェクトをクリックすると解除できます。Ctrl/Cmd を押しながらクリックしても切り替えられます。プレビューを確認してから OK を押してください。",
|
||||
@@ -1374,26 +1399,243 @@
|
||||
"from the rule": "ルールから",
|
||||
"help.apache": "Apacheライセンス2.0",
|
||||
"help.appearance.assign": "選択した立体、面、コンポーネントに、重さを変えずに色や材質の見た目を付けます。部品を見分けるときや仕上げを確認するときに使います。",
|
||||
"help.assembly.bom": "デザインまたはコンポーネントの部品を品番ごとに数量付きで一覧にし、リストをCSVまたはJSONで保存できます。発注や組み立て用の部品表として使います。",
|
||||
"help.attributions": "帰属表示 (ATTRIBUTION.md)",
|
||||
"help.build": "バージョン {version} · コミット {commit} · ビルド日 {date}",
|
||||
"help.canvas.decal": "モデルの平面にステッカーのように画像を貼ります。ラベル、ロゴ、印刷柄を部品上に表示するときに使います。",
|
||||
"help.canvas.edit": "キャンバスの位置、サイズ、角度、不透明度、反転、表示、名前を変更します。参照画像を、その上でトレースするスケッチに合わせるときに使います。",
|
||||
"help.canvas.insert": "PNG または JPEG 画像を、半透明の参照として平面や面に配置します。既知のサイズに合わせた画像をもとに、写真や図面をスケッチでトレースするときに使います。",
|
||||
"help.component.break_link": "リンクされたコンポーネントをデザイン ファイルから切り離し、ボディはそのまま残します。部品が元ファイルの変更に追従しないようにするときに使います。",
|
||||
"help.component.capture_position": "手で動かした部品の位置を、その部品の新しい位置として確定します。ジョイントで保持されていない部品をドラッグして配置した後に使います。",
|
||||
"help.component.create": "新しい空のコンポーネントをデザインに追加します。別の親を選ばない限り、アクティブなコンポーネントの中に作られます。アセンブリの新しい部品に、ボディやスケッチをまとめる場所を用意するときに使います。",
|
||||
"help.component.finish_edit": "その場で編集中の部品を保存し、アセンブリに戻って、その部品でアセンブリを更新します。リンクされた部品への変更が終わったときに使います。",
|
||||
"help.component.from_bodies": "選択した各ボディを、そのボディ名を付けた個別のコンポーネントにします。ばらばらのボディで作ったデザインを、ジョイントで結合して動かせるアセンブリにするときに使います。",
|
||||
"help.component.insert_design": "保存済みの別のデザインを、そのファイルにリンクしたコンポーネントとして挿入します。ソリッド ボディは元のデザインと同じ位置に置かれます。部品をアセンブリで再利用し、後の変更を「リンクを更新」で取り込むときに使います。",
|
||||
"help.component.properties": "コンポーネントの体積、質量、重心、慣性モーメントを、各ボディの材料から求めて表示します。アセンブリの重さやバランスを確かめるときに使います。",
|
||||
"help.component.revert_position": "手で動かした部品を元の位置に戻し、キャプチャしていない移動を破棄します。アセンブリで試しに動かした部品を元に戻すときに使います。",
|
||||
"help.component.update_links": "リンクされたデザイン ファイルを読み込み直し、変更されたボディを置き換えます。このアセンブリで使っている部品を編集した後に使います。",
|
||||
"help.config.configure": "パラメータ、フィーチャー、材料、外観を構成テーブルの列として追加します。部品のサイズ違いなど、1つのデザインのバリエーションを作るときに使います。",
|
||||
"help.config.preview": "構成テーブルの行が、デザインや履歴を変えずに再構築できるか確認します。自信のないバリエーションに切り替える前に使います。",
|
||||
"help.config.rules": "構成テーブルのルールと行、現在有効な行を表示します。デザインのバリエーションがどう設定されているかを確認するときに使います。",
|
||||
"help.config.table": "構成テーブルを表示します。1行が1つのバリエーション、1列が1つのパラメータまたはフィーチャーで、デザインが有効な行と一致しているかも分かります。デザインのバリエーションを見直すときに使います。",
|
||||
"help.connect_note": "各アシスタントを再起動すると SolidCraft サーバーが読み込まれます。変更したファイルは .bak としてバックアップされています。",
|
||||
"help.connect_title": "AI アシスタントを接続",
|
||||
"help.construct.axis.edge": "直線のエッジまたはスケッチ線に沿って構築軸を作ります。回転、円形パターン、ジョイントの軸として使います。",
|
||||
"help.construct.axis.normal_to_face": "指定した点を通り、面に垂直な構築軸を作ります。表面からまっすぐ立ち上がる軸として使います。",
|
||||
"help.construct.axis.through_cylinder": "円柱、円錐、トーラスの面、または円形のエッジの中心を通る構築軸を作ります。丸い部品のまわりでフィーチャーを回転させたりパターン化したりするときに使います。",
|
||||
"help.construct.axis.two_planes": "2つの平面または平らな面が交わる位置に構築軸を作ります。必要な軸が2つの面の間の線であるときに使います。",
|
||||
"help.construct.axis.two_points": "2つの点、頂点、スケッチ点を通る構築軸を作ります。位置が分かっている2か所の間を通る軸に使います。",
|
||||
"help.construct.plane.along_path": "エッジまたは曲線に垂直な構築平面を、その上の指定位置に作ります。スイープ用のプロファイルや、パスの断面をスケッチするときに使います。",
|
||||
"help.construct.plane.at_angle": "平面または面を、軸またはエッジを中心に指定した角度だけ傾けた構築平面を作ります。斜めのブラケットなど、傾いたスケッチに使います。",
|
||||
"help.construct.plane.midplane": "2つの平面または平らな面の中間、または角度をなして交わる場合はその二等分に構築平面を作ります。ミラーの対称面として使います。",
|
||||
"help.construct.plane.offset": "平面または平らな面に平行な構築平面を、指定した距離または点を通る位置に作ります。面から一定の高さの位置にスケッチするときに使います。",
|
||||
"help.construct.plane.perpendicular": "線またはエッジを含み、平面または面に垂直な構築平面を作ります。エッジに沿ってモデル上に垂直にスケッチするときに使います。",
|
||||
"help.construct.plane.tangent": "円柱、円錐、球、トーラスに1点で接する構築平面を作ります。丸い部品の側面にスケッチするときに使います。",
|
||||
"help.construct.plane.three_points": "3つの点を通る構築平面を作ります。3つの角など、モデル上の位置で決まる平面に使います。",
|
||||
"help.construct.plane.two_edges": "同一平面上にある2本の直線エッジまたは線を通る構築平面を作ります。向かい合う2本のエッジを通る面など、部品を横切る平面に使います。",
|
||||
"help.construct.point.along_path": "エッジまたは曲線上の指定位置に構築点を作ります。パスの途中の基準として使います。",
|
||||
"help.construct.point.center": "円形のエッジ、スケッチの円や円弧、球、トーラスの中心に構築点を作ります。穴、軸、ジョイントの基準として使います。",
|
||||
"help.construct.point.edge_plane": "エッジまたは線が平面や平らな面を通る位置に構築点を作ります。パスが平面と交わる位置を示すときに使います。",
|
||||
"help.construct.point.three_planes": "3つの平面または平らな面が交わる位置に構築点を作ります。モデルに頂点がない場所でも、角の基準として使えます。",
|
||||
"help.construct.point.two_edges": "2本のエッジまたは線が交わる位置、または最も近づく位置に構築点を作ります。仮想の角の基準として使います。",
|
||||
"help.construct.point.vertex": "頂点またはスケッチ点の上に構築点を作ります。周囲のスケッチやボディを非表示にしても残る基準として使います。",
|
||||
"help.contact.check": "接触セット内で、現在の位置で互いに食い込んでいる部品の組を一覧表示します。ジョイントを駆動したりモーション スタディを再生したりする前に、干渉を見つけるときに使います。",
|
||||
"help.contact.create": "2つ以上の部品を接触セットにまとめ、ジョイントが動くときにボディどうしが食い込まないようにします。レバーとストッパーのように、触れたところで止まるべき部品に使います。",
|
||||
"help.contact.disable_all": "接触をオフにします。ジョイントの駆動やモーション スタディは、部品が触れても止まらなくなります。部品を再び自由に動かしたいときや、大きなアセンブリの動作を軽くしたいときに使います。",
|
||||
"help.contact.edit": "接触セットを変更します。含まれる部品、名前、抑制の有無を変えられ、セットを削除することもできます。互いに食い込まないようにする部品を調整するときに使います。",
|
||||
"help.contact.enable_all": "アセンブリのすべての部品を1つの接触セットに入れ、ジョイントが動くときにどの部品どうしも食い込まないようにします。機構全体をすばやく確認するときに使います。",
|
||||
"help.contact.enable_sets": "定義した接触セットで接触をオンにします。ジョイントの駆動やモーション スタディは、セット内の部品が食い込む位置で止まります。接触をオフにした後、設定したセットに戻すときに使います。",
|
||||
"help.contact.list": "デザインの接触セット、各セットに含まれる部品、接触がオンかどうかを一覧表示します。アセンブリを駆動する前に、接触の設定を確認するときに使います。",
|
||||
"help.document.inspect": "デザインのコンポーネント、ボディ、スケッチ、フィーチャー、パラメータの概要を表示します。自分で作っていないデザインの全体像をつかむときに使います。",
|
||||
"help.document.units": "デザインで長さを表示する単位を、mmやインチなどに変更します。形状の大きさは変わらず、表示と数値だけが単位に合わせて変わります。",
|
||||
"help.edit.checkpoint": "現在のデザイン、アクティブなスケッチ、元に戻す履歴をそのまま記憶します。元に戻したくなるかもしれない危険な操作を試す前に使います。",
|
||||
"help.edit.restore_checkpoint": "元に戻す履歴も含めて、チェックポイントの状態に戻ります。チェックポイント以降の作業をまとめて破棄するときに使います。",
|
||||
"help.explode.create": "部品をアセンブリの中心から外側へ、または指定した移動量だけ離した分解図を作成します。組立手順書やプレゼンテーションで、アセンブリの組み立て方を示すときに使います。",
|
||||
"help.face.delete": "選択した面を削除し、隣の面でその穴をふさぎます。穴を開いたまま面として残すこともできます。じゃまな丸み、穴、突起を取り除くときに使います。",
|
||||
"help.file.insert_mesh": "3MF、STL、OBJ、PLY、glTF ファイルを、新しいコンポーネント内のメッシュ ボディとしてデザインに追加します。ダウンロードやスキャンで得たモデルを、参照としてデザインの横に置くときに使います。",
|
||||
"help.file.insert_step": "STEP、IGES、FreeCAD、Rhino ファイルを、新しいコンポーネント内のソリッド ボディとしてデザインに追加します。アセンブリの部品は入れ子のコンポーネントになります。メーカーやほかの CAD プログラムのモデルを取り込むときに使います。",
|
||||
"help.file.save_mesh": "ボディを STL、3MF、OBJ のメッシュとして保存します。曲面のなめらかさは選択できます。3D プリント用や、メッシュを読み込むプログラム用に部品を用意するときに使います。",
|
||||
"help.file.send_to_slicer": "選択したボディを 3MF ファイルとして保存し、選んだスライサーで開きます。モデルからプリントまでを1ステップで進めるときに使います。",
|
||||
"help.font_details": "インターフェースにはegui組み込みのフォントを使用しています(Ubuntu Font LicenceおよびMIT/Bitstream VeraライセンスのUbuntu LightとHack、OFLおよびMITのNoto Emojiと絵文字アイコンフォント)。スケッチのテキストにはLiberation Sans(SIL OFL 1.1)を使用しています。The Crafting Appsのオプションフォントパックcraft-fonts(BIZ UDPGothic、Shippori Mincho、BIZ UDMincho、Noto Sans CJK SC、Noto Sans Arabic、SIL OFL 1.1)はSolidCraftのビルドに同梱されていません。",
|
||||
"help.fonts": "フォント",
|
||||
"help.frame.member": "チューブやアルミ押し出し材などのプロファイルを、フレームスケッチの線に沿って1本につき1部材ずつ配置します。フレーム、ラック、溶接構造を作るときに使います。",
|
||||
"help.inspect.accessibility": "ツールが一方向から届く面と届かない面を色分けします。その方向からの切削加工や成形が可能か、部品を確認するときに使います。",
|
||||
"help.inspect.center_of_mass": "一様な密度を仮定して、各ボディと全体の重心を表示します。バランスや、部品が倒れる位置を確認するときに使います。",
|
||||
"help.inspect.colored_components": "外観を変えずに、コンポーネントごとに一時的な色を付けます。アセンブリの部品をひと目で見分けるときに使います。",
|
||||
"help.inspect.compare": "2つのボディを比較し、一方にだけある材料の位置を体積と偏差とともに表示します。変更した部品やインポートした部品を元のものと照合するときに使います。",
|
||||
"help.inspect.continuity": "面どうしがエッジに沿ってどれだけなめらかにつながるか(隙間、折れ、曲率の飛び)を調べ、継ぎ目を色分けします。サーフェスがきれいにつながっていない箇所を見つけるときに使います。",
|
||||
"help.inspect.curvature_comb": "曲線、エッジ、面に、曲がりの強さを歯の長さで示すコームを描きます。平らな部分、折れ、曲率のむらを見つけるときに使います。",
|
||||
"help.inspect.curvature_map": "面を曲がりの強さで色分けし、半径が小さいところを赤で示します。きつい箇所を見つけたり、サーフェスのなめらかさを判断したりするときに使います。",
|
||||
"help.inspect.draft": "面を抜き方向に対する勾配角で色分けし、不足している面を示します。成形や鋳造の前に部品を確認するときに使います。",
|
||||
"help.inspect.environment_map": "モデルを鏡のような反射する仕上げで表示します。反射の流れ方から、サーフェスの流れを判断するときに使います。",
|
||||
"help.inspect.interference": "重なっているボディを見つけ、それぞれの重なりを体積とともに表示します。アセンブリで部品が干渉していないか確認するときに使います。",
|
||||
"help.inspect.isocurve": "面のアイソパラメトリック曲線、つまりサーフェスのもとになるグリッドを描きます。サーフェスの流れや、線が密集している箇所を確認するときに使います。",
|
||||
"help.inspect.measure": "選択したものの間の長さ、距離、角度、面積、半径、またはボディの体積と質量を測定します。寸法やクリアランスを確認するときに使います。",
|
||||
"help.inspect.minimum_radius": "曲線、エッジ、面の最小曲率半径とその位置を求めます。工具やノズルが形状に沿って動けるか確認するときに使います。",
|
||||
"help.inspect.section": "モデルを変更せずに、平面でビューを切断し、切断面にハッチングを付けます。部品やアセンブリの内部を見るときに使います。",
|
||||
"help.inspect.zebra": "モデルの面に映る白黒のストライプを表示します。なめらかさの判断に使い、エッジでストライプが途切れたり折れたりする箇所は、つながりが悪いことを示します。",
|
||||
"help.joint.as_built": "2つの部品を、どちらも動かさずに現在の位置で結合し、残る動きを設定します。すでに最終的な位置に置いた部品に使います。",
|
||||
"help.joint.cam": "回転するカムとフォロワを連動させ、カムの輪郭に沿ってフォロワがスライドまたは揺動するようにします。カム、偏心機構、バルブ駆動に使います。",
|
||||
"help.joint.create": "選んだジョイント原点で2つの部品を結合し、2つ目の部品をその位置へ移動します。残る動きはジョイントの種類で決まります。実際の機構と同じように動くアセンブリを作るときに使います。",
|
||||
"help.joint.drive": "ジョイントの角度または距離を制限の範囲内で設定し、部品をそれに合わせて動かします。連動するジョイントや閉ループも追従します。機構が意図どおりに動くか確認するときに使います。",
|
||||
"help.joint.gear": "2つの回転ジョイントをギア比で連動させ、一方を駆動するともう一方が回るようにします。平歯車や内歯車に使い、ギア比はピッチ半径または歯数から決めます。",
|
||||
"help.joint.limits": "ジョイントが回転またはスライドできる範囲を最小値と最大値で設定するか、その制限を解除します。ヒンジ、スライダー、レバーを実際の可動範囲内に収めるときに使います。",
|
||||
"help.joint.motion_link": "2つのジョイントを比率とオフセットで連動させ、一方を駆動するともう一方が動くようにします。「ギア」「ラック アンド ピニオン」「ねじ」では表せない、ジョイント間の一定の関係に使います。",
|
||||
"help.joint.origin": "部品に名前付きのジョイント原点を置きます。面や丸い端の中心、エッジの中点、角、または点に置けます。ジョイントの取り付け位置を準備するときに使います。面上で選んだ原点は、部品のサイズが変わってもその面に追従します。",
|
||||
"help.joint.rack_pinion": "回転するピニオンとスライドするラックを連動させ、ピニオンのピッチ円が転がった長さだけラックが移動するようにします。ラック駆動、ステアリング、リニア ステージに使います。",
|
||||
"help.joint.reach": "部品上の点を目標に向けて動かし、そのチェーン上のジョイントを制限の範囲内で変化させます。ロボット アームの先端のように、先端の位置から機構の姿勢を決めるときに使います。",
|
||||
"help.joint.rigid_group": "選択した部品を現在の配置のまま固定し、一体として動くようにします。互いに動きのない、ひとまとまりの部品に使います。",
|
||||
"help.joint.screw": "回転とスライドをピッチで連動させ、1回転ごとにその距離だけ進むようにします。送りねじ、ボルト、ねじ軸に使います。",
|
||||
"help.library.apply": "ローカルのライブラリファイルから材料または外観を、ボディ、面、コンポーネントに適用します。別のデザインで保存した材料を再利用するときに使います。",
|
||||
"help.library.export": "デザインの材料と外観をライブラリファイルに保存します。共有したり、ほかのデザインで再利用したりするときに使います。",
|
||||
"help.library.inspect": "デザインを変更せずに、ライブラリファイルを確認して材料と外観を一覧にします。適用する前にライブラリの中身を確認するときに使います。",
|
||||
"help.licences": "ライセンス",
|
||||
"help.material.assign": "選択した立体の材料を、鋼、アルミニウム、ABS などに設定します。質量と重さを実際の部品に合わせるときに使います。",
|
||||
"help.material.properties.validate": "材料データカードの数値に矛盾や欠けがないか確認します。質量や剛性の計算にデータを使う前に使います。",
|
||||
"help.mesh.convert": "STLなどのメッシュボディを、平面と円柱面を持つ編集可能なソリッドに作り直します。インポートした機械部品を、モデリングしたボディのように変更するときに使います。",
|
||||
"help.mit": "MITライセンス",
|
||||
"help.motion.study": "タイムライン上のステップごとにジョイントの値を設定し、アニメーションとして再生します。機構が一連の動作をする様子を見て、途中のすき間を確認するときに使います。",
|
||||
"help.motion.trace": "モーション スタディの再生中やジョイントの駆動中に部品上の点がたどる軌跡を求め、確定すると3D スケッチ曲線として残します。機構の届く範囲を確認したり、その軌跡をモデリングに利用したりするときに使います。",
|
||||
"help.notice": "NOTICE",
|
||||
"help.occurrence.ground": "部品をその場に固定するか、固定を解除します。ジョイントはほかの部品をこの部品の周りで動かします。アセンブリの残りが組み付けられるフレームやベースに使います。",
|
||||
"help.occurrence.move": "アセンブリ部品をジョイントが許す自由度だけで動かします。部品の面を選択してから、操作可能な矢印または円弧をドラッグしてください。",
|
||||
"help.parameters.change": "デザインの寸法を決める名前付きの値と式の表を開きます。1か所で寸法を変え、それを使うすべてのフィーチャに反映させるときに使います。",
|
||||
"help.parameters.export": "デザインのパラメータをCSVまたはJSONで保存します。表計算ソフトで編集したり、別のデザインに移したりするときに使います。",
|
||||
"help.parameters.graph": "どのパラメータとフィーチャーがほかのどれを使っているか、その間のループやエラーも表示します。パラメータを変更すると何に影響するかを確認するときに使います。",
|
||||
"help.parameters.import": "CSVまたはJSONからパラメータをデザインに読み込みます。すべて読み込むか、まったく読み込まないかのどちらかです。表計算ソフトや別のデザインの値を取り込むときに使います。",
|
||||
"help.parameters.move": "ユーザーパラメータを、一覧内の別のパラメータの前または後ろに移動します。関連するパラメータをまとめておくときに使います。",
|
||||
"help.parts.fastener": "選んだサイズの標準のボルト、ナット、ワッシャー、ピン、ベアリングを追加します。穴の上に置くとジョイントで穴に収まるので、締結部品を自分でモデリングする必要はありません。",
|
||||
"help.parts.insert": "選んだ種類、サイズ、長さの標準パーツを挿入します。穴の縁や内壁に置くと、剛体ジョイントで穴に取り付けられます。",
|
||||
"help.parts.library": "標準パーツを開きます。ボルト、ナット、ワッシャー、止めねじ、ダウエル ピン、ベアリングを規格サイズで用意しています。標準部品を自分でモデリングせずに追加するときに使います。",
|
||||
"help.parts.resize": "挿入済みの標準パーツのサイズや長さを変更して再構築します。ジョイントにより取り付け位置は保たれます。ボルトが長すぎたときや、穴に別のサイズが必要なときに使います。",
|
||||
"help.plastic.assign_rule": "プラスチック ルールをボディに割り当て、そのプラスチックフィーチャーが勾配とクリアランスを初期値として使うようにします。成形品を一度の設定ですべてのフィーチャーに反映するときに使います。",
|
||||
"help.plastic.boss": "面にスクリューボスを追加します。穴、勾配、根元のフィレット、補強リブを任意で付けられる円柱です。成形品や3Dプリントのハウジングのねじ止め箇所に使います。",
|
||||
"help.plastic.lip": "シェルしたボディの縁に沿って、リップまたはそれに合う溝を追加します。ハウジングの2つの半体が互いに位置決めされ、しっかり閉じるようにするときに使います。",
|
||||
"help.plastic.manage_rules": "プラスチック ルール(材料、肉厚、半径、クリアランス、勾配)を作成・編集します。成形品のフィーチャーの一貫性を保つときに使います。",
|
||||
"help.plastic.rest": "面にレストを追加します。丸または四角のパッドで、中実でも中空でも、勾配を付けられます。成形ハウジングの支えやスタンドオフとして使います。",
|
||||
"help.plastic.snap_fit": "面にスナップフィットのフックを、長さ、厚さ、爪とともに追加します。ねじを使わずに部品を留めるときに使います。",
|
||||
"help.pointcloud.insert": "PLY・XYZ・PTS形式のスキャンを点群としてモデルと一緒に挿入します。計測データを参考にモデリングするときに使います。",
|
||||
"help.sheet.convert": "厚さが均一なプレートまたはシェルしたボディを、選択したエッジで曲げた板金ボディにします。既存の部品を展開できるようにするときに使います。",
|
||||
"help.sheet.export_bend_table": "板金ボディの曲げテーブル、つまり角度、半径、展開図上の曲げ位置をCSVまたはJSONで保存します。プレスブレーキや工場向けに使います。",
|
||||
"help.sheet.export_dxf": "展開図を、外形、曲げ線、必要に応じて曲げの注記付きでDXFに保存します。レーザー、プラズマ、ウォータージェット切断用に使います。",
|
||||
"help.sheet.flange": "フランジを追加します。スケッチから作るベースプレート、開いたスケッチ輪郭に沿った壁、または板のエッジに曲げた壁があります。板金部品を作り上げるときに使います。",
|
||||
"help.sheet.flat_pattern": "板金ボディの展開図を、寸法、切り欠き、曲げ線とともに作成します。切断する前にブランクを確認するときに使います。",
|
||||
"help.sheet.fold": "板をスケッチ線に沿って、指定した角度と半径で曲げます。フィーチャーを切り込んだ平らな板を折り曲げるときに使います。",
|
||||
"help.sheet.hem": "板のエッジを自身に折り返します。鋭いバリのない、安全で剛性のあるエッジにするときに使います。",
|
||||
"help.sheet.manage_rules": "板金ルール(厚さ、曲げ半径、Kファクター、逃げ、隙間)を作成・編集します。工場の材料や工具に合わせるときに使います。",
|
||||
"help.sheet.path_flange": "板のエッジに沿って、開いたスケッチ線の連なりに従い、連続したフランジを追加します。UやZ形のプロファイルを1ステップで作るときに使います。",
|
||||
"help.sheet.perforate": "展開した板全体に、千鳥またはグリッド状に穴のフィールドを追加します。通気口、グリル、軽量化したパネルに使います。",
|
||||
"help.sheet.refold": "展開した板金ボディを折り戻します。展開した板にフィーチャーを追加した後に使います。",
|
||||
"help.sheet.unfold": "板金ボディのすべての曲げを展開します。曲げをまたぐ穴や切り込みを追加するときに使い、その後で折り戻します。",
|
||||
"help.sketch.arc.center_point": "中心点まわりに、始点から終点までの円弧を描きます。穴や回転軸まわりの半径など、円弧の中心が決まっているときに使います。",
|
||||
"help.sketch.arc.tangent": "直線または円弧の端点から、それに正接する円弧を続けて描きます。角ではなく滑らかな曲がりでつなぎたいときに使います。",
|
||||
"help.sketch.arc.three_point": "始点から終点まで、3つ目の点を通る円弧を描きます。中心ではなく、通る点が決まっているときに使います。",
|
||||
"help.sketch.arc3d": "3D スケッチをオンにして、3点を通る正確な円弧を空間内に描きます。スケッチ平面から外れるパスやガイドレールの曲がりに使います。",
|
||||
"help.sketch.auto_constrain": "水平、平行、一致など、スケッチがほぼ満たしている拘束を追加し、完全に定義されるまで寸法を付けます。ラフに描いたスケッチを一度で固定したいときに使います。",
|
||||
"help.sketch.auto_constrain_from_datum": "自動拘束と同様ですが、原点ではなく、選んだ基準点から位置を測ります。角や穴など、1つの基準点から部品を配置するときに使います。",
|
||||
"help.sketch.blend_curve": "2本の曲線の端を、両方に正接する滑らかなスプラインでつなぎます。選べば曲率連続にもできます。曲線の間の隙間を折れ目なく埋めるときに使います。",
|
||||
"help.sketch.break": "曲線を、ほかの曲線と交差する位置、または置いた点で分割します。曲線の一部に別の拘束を付けたり、その部分だけ削除したりするときに使います。",
|
||||
"help.sketch.cancel": "スケッチを終了し、作成または編集を始めてからの変更をすべて破棄します。元に戻すで変更を復元できます。",
|
||||
"help.sketch.centerline": "直線を、通常の直線と中心線(輪郭に含まれない軸)に切り替えます。回転、ミラー、対称拘束の軸として中心線を使います。",
|
||||
"help.sketch.chamfer.distance_angle": "2本の直線の角を、1本目の直線に沿った距離と角度で面取りします。2 mm × 30° のように、図面で長さと角度が指定されているときに使います。",
|
||||
"help.sketch.chamfer.equal_distance": "2本の直線の角を、両方に同じ距離だけ戻って面取りします。外形の一般的な 45° 面取りに使います。",
|
||||
"help.sketch.chamfer.two_distance": "2本の直線の角を、それぞれの直線に沿った別々の距離で面取りします。45° ではない、2つの長さで指定された面取りに使います。",
|
||||
"help.sketch.circle.center": "中心と直径から円を描きます。中心が決まっている穴、ボス、そのほかの丸い形状に使います。",
|
||||
"help.sketch.circle.three_point": "3点を通る円を描きます。既存のジオメトリ上の点など、円が通る点が決まっているときに使います。",
|
||||
"help.sketch.circle.three_tangent": "3つの直線、円、円弧に接する円を描きます。三角形の内接円のように、3本の曲線の間に円をはめ込むときに使います。",
|
||||
"help.sketch.circle.two_point": "直径の両端の2点から円を描きます。中心ではなく、円周上の点が決まっているときに使います。",
|
||||
"help.sketch.circle.two_tangent": "2つの直線、円、円弧に接する、指定サイズの円を描きます。2本の曲線の間に半径一定の丸みを付けるときに使います。",
|
||||
"help.sketch.conic": "2つの端点の間に、頂点と rho 値で形が決まる円錐曲線を描きます。平らな形からほぼ鋭い角まで、ふくらみを調整できる滑らかな遷移に使います。",
|
||||
"help.sketch.constrainer": "選んだ1〜2本の曲線がほぼ満たしている拘束(水平、平行、正接、等長など)を適用します。手描きのスケッチを1つずつ整えるときに使います。",
|
||||
"help.sketch.constraint.coincident": "点を、別の点、曲線、スケッチ軸の上に載せます。輪郭の隙間を閉じたり、点を直線上に置いたりするときに使います。",
|
||||
"help.sketch.constraint.collinear": "2本の直線を同一直線上に揃えます。切り欠きの両側など、途切れたエッジを揃えるときに使います。",
|
||||
"help.sketch.constraint.concentric": "2つの円または円弧の中心を揃えます。リング、座ぐり、段付きシャフトに使います。",
|
||||
"help.sketch.constraint.curvature": "端点で接する2本の曲線を、同じ曲率で続けます (G2)。正接では滑らかさが足りない、見える面などに使います。",
|
||||
"help.sketch.constraint.equal": "直線を同じ長さに、円や円弧を同じ半径にします。1つの寸法で複数の同じ形状を制御するときに使います。",
|
||||
"help.sketch.constraint.fix": "点や曲線を現在の位置に固定、または固定を解除します。ドラッグやスケッチの解決で動いてはいけないジオメトリに使います。",
|
||||
"help.sketch.constraint.horizontal_vertical": "直線、または2点を結ぶ線を、近いほうに合わせて水平または垂直にします。外形をスケッチの軸に揃えるときに使います。",
|
||||
"help.sketch.constraint.midpoint": "点を直線の中央に置く、または2本の直線の中点を一致させます。エッジに対してジオメトリを中央に配置するときに使います。",
|
||||
"help.sketch.constraint.parallel": "2本の直線を平行にします。ほかの寸法を変えても平行を保つ辺に使います。",
|
||||
"help.sketch.constraint.perpendicular": "2本の直線を直角に交わらせます。スケッチ軸上にない直線同士の直角の角に使います。",
|
||||
"help.sketch.constraint.polygon": "閉じた直線の連なりを正多角形にします。辺の長さが等しく、すべての角が1つの円上に載ります。手描きの多角形を正多角形にして、そのまま保つときに使います。",
|
||||
"help.sketch.constraint.symmetry": "2つの点または曲線を、直線を挟んで、または点を中心に対称にします。片側を変更しても輪郭の対称性を保つときに使います。",
|
||||
"help.sketch.constraint.tangent": "直線と円弧など、2本の曲線を正接させます。折れ目のない滑らかな接続に使います。",
|
||||
"help.sketch.construction": "曲線を、通常のジオメトリと、輪郭に含まれないコンストラクション ジオメトリに切り替えます。レイアウト、参照、寸法の補助としてコンストラクション曲線を使います。",
|
||||
"help.sketch.construction_line": "2点を通る無限の補助直線を作成します。スケッチの輪郭を分割せずに作図できます。",
|
||||
"help.sketch.construction_line.angle": "スケッチのX軸に対して角度を指定し、無限の補助直線を作成します。点を選び、角度を入力するか方向を選びます。",
|
||||
"help.sketch.construction_line.bisector": "交差する2本のスケッチ直線を選び、2つの角の二等分線から選びます。結果は元の直線の編集に追従します。",
|
||||
"help.sketch.construction_line.horizontal": "指定点を通る無限の水平補助直線を作成します。後で編集しても水平拘束が維持されます。",
|
||||
"help.sketch.construction_line.parallel": "スケッチの直線を選び、平行な無限の補助直線を配置します。右クリックで参照を選び直します。",
|
||||
"help.sketch.construction_line.perpendicular": "スケッチの直線を選び、直交する無限の補助直線を配置します。右クリックで参照を選び直します。",
|
||||
"help.sketch.construction_line.tangent_at": "円や円弧上の点、または開いたスプラインや円錐曲線の端点に接線を作成します。曲線を選び、接点を選びます。",
|
||||
"help.sketch.construction_line.tangent_external": "円または円弧、外部点、接線の解を順に選びます。プレビューには描かれた円弧上の接点のみが表示されます。",
|
||||
"help.sketch.construction_line.tangent_two": "2つの円または円弧を選び、プレビューから共通接線を選びます。接点は描かれた曲線上にある必要があります。",
|
||||
"help.sketch.construction_line.vertical": "指定点を通る無限の垂直補助直線を作成します。後で編集しても垂直拘束が維持されます。",
|
||||
"help.sketch.copy": "選んだスケッチの曲線と点を、その間の拘束や寸法とともにコピーします。このスケッチまたは別のスケッチに貼り付けられます。",
|
||||
"help.sketch.create": "平面、またはモデルの平らな面に、新しい 2D スケッチを開始します。押し出し、回転、スイープはすべてスケッチから始まります。",
|
||||
"help.sketch.cut": "選んだスケッチ ジオメトリをコピーしてスケッチから削除します。操作は1回で元に戻せます。このスケッチ内の別の場所や別のスケッチに貼り付けられます。",
|
||||
"help.sketch.dimension": "選んだ対象に応じて、長さ、距離、角度、半径、直径の駆動寸法を追加します。値またはパラメーター名を入力すると、スケッチがそれに追従します。",
|
||||
"help.sketch.edit": "既存のスケッチを開いて編集します。スケッチを終了すると、それをもとにしたフィーチャが更新されます。",
|
||||
"help.sketch.ellipse": "中心、長軸の端、短軸側の1点から楕円を描きます。長円形の開口部、カム、そのほか細長い丸い形に使います。",
|
||||
"help.sketch.equation_curve": "x(t) と y(t)、または y = f(x) の式から、範囲を指定して曲線を描きます。式にはパラメーターを使え、曲線はその変更に追従します。正弦波、らせん、歯車のインボリュートなどに使います。",
|
||||
"help.sketch.extend": "直線または円弧を、行く手にある最も近い曲線まで延長します。2本の曲線を交わるまで伸ばすこともできます。トリムや編集のあとに輪郭の隙間を閉じるときに使います。",
|
||||
"help.sketch.fillet": "2本の直線または円弧が交わる角を、指定した半径の円弧で丸めます。まとめて丸めた複数の角は同じ半径になります。",
|
||||
"help.sketch.finish": "スケッチを終了してモデルに戻ります。閉じた輪郭は、押し出し、回転などのフィーチャに使えるようになります。",
|
||||
"help.sketch.finish_auto_constrain": "スケッチに自動拘束を実行してから終了します。スケッチを完全に定義した状態で一度に終えるときに使います。",
|
||||
"help.sketch.fit_curves_to_section": "メッシュまたはソリッド ボディをスケッチ平面で切り、断面に直線と円弧をフィットさせます。スキャンや読み込んだ部品を編集可能なスケッチとして作り直すときに使います。",
|
||||
"help.sketch.include_3d": "モデルのエッジ、頂点、ほかのスケッチの曲線を、リンクされた参照としてこのスケッチに取り込み、平面外のものは平面上に平坦化します。スケッチ平面上にないジオメトリをもとに作図するときに使います。",
|
||||
"help.sketch.infinite": "直線を、通常の直線と、ビュー全体に伸びる無限の補助直線に切り替えます。短すぎて足りなくなることのない、レイアウトの参照として使います。",
|
||||
"help.sketch.insert_dxf": "DXF 図面の曲線をスケッチに読み込み、指定した位置に拡大縮小・回転して配置します。レーザー加工の外形など、ほかのプログラムで作った2D 図面をもとにモデリングするときに使います。",
|
||||
"help.sketch.insert_svg": "SVG 図面のパスをスケッチに読み込み、指定した位置に拡大縮小・回転して配置します。ロゴやベクター輪郭を、押し出しできる曲線にするときに使います。",
|
||||
"help.sketch.inspect": "開いているスケッチのレポートを開きます。残りの自由度と、完全に拘束されているかどうかを表示します。スケッチを終える前に、まだ動く部分を確認するときに使います。",
|
||||
"help.sketch.intersect": "ボディ、面、エッジ、ほかのスケッチがスケッチ平面と交差する曲線または点を追加します。リンクが保たれ、モデルが変わると追従します。",
|
||||
"help.sketch.intersection_curve": "2つのボディまたは面が接する位置に、それらにリンクした 3D 曲線を作成します。モデルに追従するパスやガイドレールとして使います。",
|
||||
"help.sketch.isoparametric_curve": "選んだ点を通る面の U または V 方向に沿った 3D 曲線を、面にリンクして作成します。表面に追従するパスや分割線として使います。",
|
||||
"help.sketch.line": "点を順に指定して、つながった直線を開いた連なりまたは閉じた外形として描きます。ほとんどの輪郭に使う基本のツールです。",
|
||||
"help.sketch.line.midpoint": "中点から一方の端まで直線を描き、もう一方の端は反対側に対称に作られます。対称なエッジなど、点を中心にした直線に使います。",
|
||||
"help.sketch.line3d": "3D スケッチをオンにして、空間内の点の間につながった直線を描きます。スケッチ平面から外れるパスやフレームに使います。",
|
||||
"help.sketch.mirror": "スケッチの曲線と点を直線または軸に対してミラーし、対称拘束を追加します。対称な輪郭の半分を描いて完成させるときに使います。",
|
||||
"help.sketch.move": "スケッチの曲線と点、またはそのコピーを移動または回転します。形状と拘束を保ったままジオメトリの位置を変えるときに使います。",
|
||||
"help.sketch.offset": "曲線の連なりを、指定した距離で片側または両側にコピーします。壁、外形、クリアランスに使い、距離は編集可能な寸法のままです。",
|
||||
"help.sketch.paste": "コピーまたは切り取ったスケッチ ジオメトリを、アクティブなスケッチに貼り付けます。点を指定して配置するか、オフセットでずらせます。",
|
||||
"help.sketch.pattern.circular": "スケッチ ジオメトリを中心点まわりに、全周または指定角度でコピーします。ボルト円、スポーク、歯に使います。",
|
||||
"help.sketch.pattern.rectangular": "スケッチ ジオメトリを、指定した間隔で行と列にコピーします。穴、スロット、通気口の格子に使います。",
|
||||
"help.sketch.point": "スケッチ点を配置します。寸法、拘束、穴の中心、後のフィーチャの参照として使います。",
|
||||
"help.sketch.point3d": "3D スケッチをオンにして、空間内に点を配置します。3D 曲線やパスの参照として使います。",
|
||||
"help.sketch.polygon.circumscribed": "円の外側に接する正多角形を、中心から辺の中央までのサイズで描きます。六角ナットのように、二面幅が決まっているときに使います。",
|
||||
"help.sketch.polygon.edge": "1辺の両端から正多角形を描きます。辺の長さと位置が決まっているときに使います。",
|
||||
"help.sketch.polygon.inscribed": "円に内接する正多角形を、中心から角までのサイズで描きます。対角のサイズが決まっているときに使います。",
|
||||
"help.sketch.project": "モデルのエッジ、面、頂点、ほかのスケッチの曲線を、このスケッチの平面に投影して取り込みます。リンクが保たれ、モデルが変わると追従します。",
|
||||
"help.sketch.project_to_surface": "ほかのスケッチの曲線を、このスケッチの法線方向に沿って面へ投影し、リンクされた 3D 曲線にします。ロゴ、分割線、パスを曲面に載せるときに使います。",
|
||||
"help.sketch.rectangle.center": "中心と1つの角から長方形を描きます。原点など、点を中心にした外形に使います。",
|
||||
"help.sketch.rectangle.rounded": "4つの角をすべて同じ半径で丸めた長方形を描きます。角の丸いプレート、フタ、開口部に使います。",
|
||||
"help.sketch.rectangle.three_point": "1辺と、反対側の1点から長方形を描きます。スケッチ軸に対して傾いた長方形に使います。",
|
||||
"help.sketch.rectangle.two_point": "対角の2点から長方形を描きます。プレート、ブロック、ポケットの外形に使います。",
|
||||
"help.sketch.scale": "スケッチの曲線と点を、基準点を中心に倍率で拡大縮小します。描き直さずにスケッチの一部のサイズを変えるときに使います。",
|
||||
"help.sketch.slot.arc_center": "中心、始点、終点で決まる円弧に沿って、指定幅の曲線スロットを描きます。回転軸まわりの調整用スロットに使います。",
|
||||
"help.sketch.slot.arc_three_point": "3点を通る円弧に沿って、指定幅の曲線スロットを描きます。スロットの経路が決まった点を通る必要があるときに使います。",
|
||||
"help.sketch.slot.center_point": "中心から一方の端の円弧の中心まで、指定幅の直線スロットを描きます。点を中心にしたスロットに使います。",
|
||||
"help.sketch.slot.center_to_center": "両端の円弧の中心の間に、指定幅の直線スロットを描きます。ネジの調整用スロットなど、中心間で寸法を指定するスロットに使います。",
|
||||
"help.sketch.slot.overall": "一方の外端からもう一方の外端まで、指定幅の直線スロットを描きます。スロットの全長が重要なときに使います。",
|
||||
"help.sketch.spline.control_point": "通らない制御点で形が決まる3次スプラインを描きます。点を動かして形を整える、滑らかで流れるような曲線に使います。",
|
||||
"help.sketch.spline.control_point_5": "制御点で形が決まる5次スプラインを描きます。見えるスタイリング面など、より滑らかな曲率で曲線をつなぎたいときに使います。",
|
||||
"help.sketch.spline.fit_point": "置いたすべての点を通る滑らかなスプラインを、開いた形または閉じた形で描きます。既知の点を通して形をなぞるときに使います。",
|
||||
"help.sketch.spline3d": "3D スケッチをオンにして、点を通る滑らかな曲線を空間内に描きます。スケッチ平面から外れるスイープ パスやケーブルの経路に使います。",
|
||||
"help.sketch.spun_profile": "軸まわりに回転したボディが描く外形を、スケッチ平面上に作成します。回転や図面のために、旋削部品のシルエットを得るときに使います。",
|
||||
"help.sketch.text": "選んだフォント、高さ、角度でスケッチに文字を書きます。文字はパラメーターに追従させられます。押し出しやエンボスでラベルや文字にします。",
|
||||
"help.sketch.transform": "スケッチ ジオメトリを、中心点まわりに拡大縮小、回転、移動を一度に行います。選択した対象の位置とサイズをまとめて変えるときに使います。",
|
||||
"help.sketch.trim": "クリックした位置の前後で、最も近い交差の間にある曲線の部分を削除します。重なった線を整えて閉じた輪郭にするときに使います。",
|
||||
"help.solid.align": "選択した立体を動かし、その点、面、平面を別の場所の点、面、平面に合わせます。距離を測らずに部品を別の部品に当てて配置するときに使います。",
|
||||
"help.solid.boundary_fill": "重なり合うツール ボディに囲まれた領域からソリッドを作成し、選んだ領域だけを埋めます。複数のボディが囲む空間から形状を作るときに使います。",
|
||||
"help.solid.bounding_solid": "選択したボディを囲むボックスを作成します。余裕寸法も指定できます。部品の全体寸法の確認や、加工前の素材形状として使います。",
|
||||
"help.solid.box": "長さ、幅、高さからボックスを作成します。角の点から、または点を中心に配置できます。簡単なブロック、仮の形状、フィーチャを切り込む元のボディに使います。",
|
||||
"help.solid.chamfer": "選択した辺を、指定した距離で平らに斜めに削ります。鋭い角を落とすときや、ピンやねじを入れやすくするときに使います。",
|
||||
"help.solid.coil": "直径、巻数、高さまたはピッチと、丸または角の断面から、ばねのようならせん状のボディを作成します。ばね、コイル、らせん状の突起に使います。",
|
||||
"help.solid.combine": "複数の立体を結合したり、対象の立体から切り取ったり、共通する体積だけを残したりでき、工具の立体を残すこともできます。部品の結合、ある形での切り抜き、2つの立体が重なる範囲の確認に使います。",
|
||||
"help.solid.cone": "底面の円と高さから円錐を作成します。上面にも半径を指定すると円錐台になります。テーパー、漏斗、皿穴、先端部に使います。",
|
||||
"help.solid.cylinder": "半径または直径と高さから、点の上に軸方向に立つ円柱を作成します。シャフト、ピン、ボス、丸い素材に使います。",
|
||||
"help.solid.draft": "選択した面を、中立面から測った指定の角度だけ傾けます。成形品や鋳物の部品を型から抜けるようにするときに使います。",
|
||||
"help.solid.emboss": "テキストやロゴなどのスケッチ プロファイルを、面から浮き出させるか面に彫り込みます。平面や円筒面の文字、ラベル、刻印に使います。",
|
||||
"help.solid.extrude": "スケッチの輪郭を指定した距離だけ立体方向に押し出し、材料を足したり削ったりします。平面の図形をブロック、突起、ポケットにするときに使います。",
|
||||
"help.solid.fillet": "選択した辺を、指定した半径のなめらかな円弧で丸めます。強度や持ちやすさ、見た目のために鋭い角を和らげるときに使います。",
|
||||
"help.solid.hole": "面上の指定した位置に、指定した直径の丸い穴をあけます。ねじのクリアランスやピン穴など、単純な丸い開口に使います。",
|
||||
@@ -1402,20 +1644,60 @@
|
||||
"help.solid.move": "選択した立体、またはそのコピーを、指定した距離と角度で移動・回転します。立体の位置を変えるときや、別の場所にもう1つ作るときに使います。",
|
||||
"help.solid.offset_face": "選択した面を指定した距離だけ内側または外側へ動かし、周りの面もそれに合わせます。スケッチを編集せずに、壁を厚く、ポケットを深く、突起を高くするときに使います。",
|
||||
"help.solid.pattern.circular": "選択したオブジェクトを、指定した数と全体の角度で軸のまわりに繰り返し配置します。ボルト円、スポーク、フィン、歯などに使います。",
|
||||
"help.solid.pattern.path": "フィーチャーまたはボディを、スケッチのパスに沿って個数と間隔を指定してコピーします。曲線エッジに沿った穴や、レールに沿った部品に使います。",
|
||||
"help.solid.pattern.rectangular": "選択したオブジェクトを、指定した数と間隔で1方向または2方向に繰り返し配置します。穴、リブ、ピン、脚の列や格子状の配置に使います。",
|
||||
"help.solid.pipe": "スケッチ曲線の経路に沿って、中実または肉厚付きの中空の丸パイプを作成します。チューブ、ワイヤー、ケーブル、手すりに使います。",
|
||||
"help.solid.press_pull": "面をドラッグして材料を足したり削ったりし、辺をドラッグして丸めます。モデル上で直接すばやく変更するときに使います。",
|
||||
"help.solid.remove": "タイムラインのこの位置から先で、選択した立体をデザインから取り除きます。それより前のステップには残ります。不要になった切り取り用の立体など、補助の立体を外すときに使います。",
|
||||
"help.solid.replace_face": "選択した平らな面を平面または平行な面の位置へ動かし、立体はそこまで伸び縮みします。面を別の部品や作業平面と面一にするときに使います。",
|
||||
"help.solid.revolve": "スケッチの輪郭を軸のまわりに回転させ、丸い立体を作ります。軸、つまみ、ボウルなど、中心線まわりに丸い部品に使います。",
|
||||
"help.solid.rib": "開いたスケッチ曲線に沿って、ボディの次の面まで届く薄い壁を追加します。成形品や 3D プリント部品などで、壁や角を補強するときに使います。",
|
||||
"help.solid.scale": "選択した立体を、全方向に同じ倍率、または軸ごとの倍率で拡大・縮小します。読み込んだ形状の大きさを変えるときや、収縮分を見込むときに使います。",
|
||||
"help.solid.shell": "立体の中をくり抜き、指定した厚さの壁を残します。選んだ面を開口にすることもできます。箱、カバーなどの薄肉の部品に使います。",
|
||||
"help.solid.sphere": "中心点の周りに、半径または直径から球を作成します。ボール、つまみ、丸い端部に使います。",
|
||||
"help.solid.split_body": "平面、別の立体の面、またはスケッチの線で、立体を別々の立体に分割します。別々に印刷、加工、着色する部品を作るときに使います。",
|
||||
"help.solid.split_face": "選択した面を、平面、別の立体の面、またはスケッチの曲線に沿って分割します。立体そのものは切りません。面の一部にだけ抜き勾配、色、オフセットを付けるときに使います。",
|
||||
"help.solid.sweep": "スケッチの輪郭をパスに沿って動かし、立体を作ります。パイプ、レール、ハンドルなど、一定の断面で曲線をたどる部品に使います。",
|
||||
"help.solid.thread": "円筒面に ISO メートルねじを追加します。表示上のねじにするか、ボディに切り込むかを選べます。ボルト、ねじ穴、3D プリントのねじ部品に使います。",
|
||||
"help.solid.torus": "軸周りの大半径と、丸い断面の小半径からリングを作成します。O リング、取っ手、丸いビードに使います。",
|
||||
"help.solid.web": "開いたスケッチ曲線ごとに、ボディの次の面まで届く薄い壁を追加します。ハウジングやトレイ内部の格子状の補強壁に使います。",
|
||||
"help.surface.blend": "2つのボディのエッジを橋渡しするサーフェスを、両方に接線連続または曲率連続で作ります。隙間を越えて2つのサーフェスをなめらかにつなぐときに使います。",
|
||||
"help.surface.boundary": "2〜4本のスケッチ曲線のループ、または曲線ネットワークを埋めるサーフェスを作ります。エッジで定義される自由曲面のパネルに使います。",
|
||||
"help.surface.extend": "サーフェスをエッジの先へ、指定した距離または平面や面まで延長します。トリムやステッチの前に、サーフェスどうしを重ねるために使います。",
|
||||
"help.surface.extrude": "スケッチ曲線またはプロファイルを指定した距離だけ押し出し、キャップのない壁だけのサーフェスにします。薄い壁や、切断・分割用のツールに使います。",
|
||||
"help.surface.fair": "エッジを動かさずに、自由曲面の内部をなめらかにします。サーフェスの凹凸や、波打つ反射をならすときに使います。",
|
||||
"help.surface.loft": "2つ以上の断面を順に通るサーフェスを、キャップなしで作ります。シェルや、異なる形状の間の移行部に使います。",
|
||||
"help.surface.match": "サーフェスのエッジを作り直し、別のボディのエッジに接線または曲率を合わせてつなぎます。2つのサーフェスの継ぎ目をなめらかに閉じるときに使います。",
|
||||
"help.surface.offset": "面を法線方向に指定した距離だけ離したコピーを、新しいサーフェスボディとして作ります。スキン、クリアランス、壁の反対側を作るときに使います。",
|
||||
"help.surface.patch": "スケッチ領域またはエッジの閉ループを、平らな面またはなめらかに湾曲した面で埋めます。サーフェスボディの穴を塞ぐときに使います。",
|
||||
"help.surface.reverse_normal": "サーフェスボディの面を裏返して、外側の向きを反対にします。面が内向きになっているとき、厚み付けやステッチの前に使います。",
|
||||
"help.surface.revolve": "スケッチ曲線またはプロファイルを軸のまわりに回転させ、キャップのないサーフェスにします。ランプシェード、ボウル、ノズルなどの丸いシェルに使います。",
|
||||
"help.surface.ruled": "エッジの連なりから、面の法線方向、接線方向、または指定した角度に、直線でできた帯を作ります。勾配のある壁、ランオフ、分割面に使います。",
|
||||
"help.surface.stitch": "サーフェスボディを共有するエッジで縫い合わせ、閉じる場合はソリッドにします。複数のサーフェスを1つのボディにまとめるときに使います。",
|
||||
"help.surface.sweep": "スケッチ曲線またはプロファイルをパスに沿って動かし、キャップのないサーフェスにします。雨どいやトリムなど、パスに沿う薄い形状に使います。",
|
||||
"help.surface.thicken": "サーフェスボディに厚みを与えて、ソリッドにします。サーフェスから3Dプリントや機械加工ができる部品を作るときに使います。",
|
||||
"help.surface.trim": "平面、別のサーフェス、スケッチ曲線でサーフェスを切断し、選んだ側を残します。ステッチの前にサーフェスを形に切り出すときに使います。",
|
||||
"help.surface.unstitch": "ボディの面を、個別のサーフェスボディに分離します。ソリッドはサーフェスにばらばらになります。ボディの一部の面だけを作り直すときに使います。",
|
||||
"help.surface.untrim": "面から穴を取り除くか、外側の境界をサーフェス本来の範囲に戻します。トリムした後で、元のサーフェス全体を取り戻すときに使います。",
|
||||
"help.third_party": "サードパーティライセンス",
|
||||
"help.timeline.compute_all": "タイムラインのすべてのフィーチャを最初から作り直します。モデルを更新し、どのフィーチャが失敗するかを確認するときに使います。",
|
||||
"help.timeline.delete": "選択したフィーチャをタイムラインから削除します。スケッチを削除すると、そこから作ったフィーチャも削除されます。不要になったステップを取り除くときに使います。",
|
||||
"help.timeline.dependents": "フィーチャーと一緒に削除されるフィーチャーと、それがないと失敗するフィーチャーを一覧にします。フィーチャーを削除または変更する前に使います。",
|
||||
"help.timeline.play": "残りのフィーチャを一つずつ再生し、再構築のたびに0.5秒間停止します。このコマンドをもう一度実行するかEscキーで停止し、「最後へ」で直ちに最後へ移動します。",
|
||||
"help.view.apply": "ビューをフロント、トップ、アイソメなどの標準方向、または保存した名前付きビューに回転します。固定した角度からモデルを見るときに使います。",
|
||||
"help.view.delete": "保存した名前付きビューを削除します。モデルは変更されません。",
|
||||
"help.view.fit": "モデル全体、または選択したものがビューいっぱいになるように、ズームと移動をします。モデルが視界から外れたときに使います。",
|
||||
"help.view.grid": "ビューポートのグリッドを表示または非表示にします。モデリング中の大きさと向きの目安として使います。",
|
||||
"help.view.ground_shadow": "地面に落ちるモデルの影を表示または非表示にします。高さや位置を判断しやすくするときに使います。",
|
||||
"help.view.home": "ビューをホームの方向に戻し、モデルをフィットさせます。決まったビューにすばやく戻るときに使います。",
|
||||
"help.view.list": "デザインに保存されている名前付きビューを一覧にします。以前に保存したビューを探すときに使います。",
|
||||
"help.view.navigate": "左に90度回転するなど、ステップごとにビューを回転、移動、ズームします。ドラッグではなく、カメラを正確に動かすときに使います。",
|
||||
"help.view.navigation_bar": "ビューポート下部のナビゲーションバーを表示または非表示にします。広く使いたいときは非表示に、マウスでビューツールを使うときは表示にします。",
|
||||
"help.view.rename": "保存した名前付きビューの名前を変更します。ビュー自体は変わりません。",
|
||||
"help.view.save": "現在のカメラ位置を名前付きビューとしてデザインに保存します。スクリーンショット用など、後で同じ角度に戻るときに使います。",
|
||||
"help.view.spin": "次のクリックまたはキー操作まで、モデルのまわりでビューを連続して周回させます。モデルをあらゆる方向から見せるときに使います。",
|
||||
"help.view.tool": "オービット、パン、ズームのカメラツールを固定し、オフにするまで左ボタンのドラッグでビューを動かせるようにします。トラックパッドや、中ボタンのないマウスで使います。",
|
||||
"help.view.visual_style": "モデルの描画方法(エッジ付きまたはなしのシェード、ワイヤーフレーム、隠線付き)を切り替えます。内部を見るにはワイヤーフレーム、すっきり見せるにはシェードを使います。",
|
||||
"history.sketch_under_constrained": "拘束不足(自由度 {count})",
|
||||
"history.sketch_under_constrained_one": "拘束不足(自由度 {count})",
|
||||
"hole_presets.confirm_delete": "削除を確認",
|
||||
@@ -1592,6 +1874,10 @@
|
||||
"material.selection.mixed": "異なる材料",
|
||||
"measure.at": "位置",
|
||||
"measure.item": "項目 {number}",
|
||||
"measure.quick_copied": "測定値をコピーしました",
|
||||
"measure.quick_copy": "クリックで測定値をコピー",
|
||||
"measure.quick_edges": "エッジ {count} 本",
|
||||
"measure.quick_faces": "面 {count} 個",
|
||||
"messages.ago_h": "{n} 時間前",
|
||||
"messages.ago_min": "{n} 分前",
|
||||
"messages.ago_s": "{n} 秒前",
|
||||
@@ -1625,6 +1911,7 @@
|
||||
"nav.hfss.help": "Alt+左ドラッグでパン、Shift+Alt+左ドラッグでズーム、何もない所からの Ctrl+左ドラッグで回転。",
|
||||
"nav.inventor.help": "中ドラッグでパン、Shift+中ドラッグで回転、Ctrl+中ドラッグでズーム、右ドラッグで回転。",
|
||||
"nav.maya.help": "Alt+左ドラッグで回転、Alt+中ドラッグでパン、Alt+右ドラッグでズーム。中ドラッグでもパン。",
|
||||
"nav.nx.help": "中ボタンのドラッグで回転、Shift+中ボタンで平行移動(NXの中ボタン+右ボタン)、Ctrl+中ボタンでズーム(NXの中ボタン+左ボタン)。右ボタンのドラッグではカメラは動きません",
|
||||
"nav.openscad.help": "空きスペースで左ドラッグすると回転、Shift+左ドラッグで矩形選択、スケッチ ジオメトリはドラッグで編集。右または中ドラッグでパン、Shift+右または Shift+中ドラッグでズーム。",
|
||||
"nav.perspective.sketch": "スケッチ編集中は平行投影で表示されます。透視投影に切り替えるにはスケッチを終了してください。",
|
||||
"nav.right_drag_orbits.help": "オフ:右ドラッグではカメラは動かず、右ボタンはコンテキストメニューを開くだけです。マウス割り当てで SolidWorks を選ぶとオフになります。",
|
||||
@@ -1744,6 +2031,11 @@
|
||||
"not a move": "移動ではありません",
|
||||
"not a number": "数値ではありません",
|
||||
"open a sketch first": "先にスケッチを開いてください",
|
||||
"parameters.apply_live": "フィールドを離れるたびに変更を適用",
|
||||
"parameters.apply_live_tip": "オフ: 変更は「適用」または「OK」まで保留され、その後すべてをまとめて一度だけ再構築します。「キャンセル」または Esc で破棄します。",
|
||||
"parameters.held": "{count} 件の変更が適用待ちです",
|
||||
"parameters.held_hint": "式と単位を編集してください。変更は「適用」または「OK」まで保留されます。",
|
||||
"parameters.held_one": "1 件の変更が適用待ちです",
|
||||
"parts.automatic_name": "自動",
|
||||
"parts.dimension.across_flats": "二面幅",
|
||||
"parts.dimension.bore": "内径",
|
||||
@@ -1766,6 +2058,8 @@
|
||||
"parts.family.set_screw": "六角穴付き止めねじ 平先",
|
||||
"parts.family.socket_head_cap_screw": "六角穴付きボルト",
|
||||
"parts.family.washer": "平座金",
|
||||
"parts.holes": "穴 (省略可)",
|
||||
"parts.placement_hint": "1 つ以上の穴を選ぶとそれぞれに部品を取り付けます。選ばずに OK を押すと原点に配置します",
|
||||
"pattern.alignment_2": "配置 2",
|
||||
"pattern.alignment_hint": "個数には元の図形が含まれます。中央配置ではコピーを両側に配置し、反転で偶数個の場合に多く配置する側を切り替えます。",
|
||||
"pattern.direction_1": "方向 1",
|
||||
@@ -1818,6 +2112,8 @@
|
||||
"prefs.bottom_centre": "下中央",
|
||||
"prefs.bottom_right": "右下",
|
||||
"prefs.browser": "ブラウザー",
|
||||
"prefs.browser_eye_left": "表示切り替えを折りたたみ矢印の隣に表示",
|
||||
"prefs.browser_eye_left_note": "ブラウザーの各行の表示切り替えを、行の右端の列ではなく、以前のように折りたたみ矢印の隣に表示します。",
|
||||
"prefs.browser_reveal_on_hover": "ホバーで表示",
|
||||
"prefs.browser_show_note": "「表示」はブラウザーを常に画面に表示します。「ホバーで表示」はポインターがその位置か左端の細いタブに来るまで隠し、ポインターが中にある間やそのメニューが開いている間は表示したままにします。",
|
||||
"prefs.browser_shown": "表示",
|
||||
@@ -1837,6 +2133,8 @@
|
||||
"prefs.ctrl_cmd": "Ctrl / Cmd",
|
||||
"prefs.curved_surfaces": "曲面",
|
||||
"prefs.curves": "曲面",
|
||||
"prefs.dark_parts_shading": "暗い部品の形状を保つ",
|
||||
"prefs.dark_parts_shading_help": "リニア光と柔らかいスカイライトでビューをシェーディングし、暗い面が黒くつぶれずにグラデーションを保つようにします",
|
||||
"prefs.dead_zone_note": "斜線の帯はデッドゾーンです。この範囲内の動きは無視されます。",
|
||||
"prefs.default": "既定",
|
||||
"prefs.design": "設計の既定値",
|
||||
@@ -1851,6 +2149,8 @@
|
||||
"prefs.edges": "エッジと陰影",
|
||||
"prefs.extend": "拡張",
|
||||
"prefs.extra_navigation": "何もない場所でCtrl+左ドラッグすると回転し、Spaceを押しながらドラッグすると移動します。",
|
||||
"prefs.extrude_view_isometric": "押し出しを開いたときに等角ビューにする",
|
||||
"prefs.extrude_view_return": "押し出しを閉じたときに元のビューに戻す",
|
||||
"prefs.follows_os": "OS の設定に従う",
|
||||
"prefs.font": "フォント",
|
||||
"prefs.font_fallback": "選択したフォントにない文字は組み込みフォントで表示し、ラベルが空の四角になるのを防ぎます。",
|
||||
@@ -1866,8 +2166,11 @@
|
||||
"prefs.graphics_card_auto": "自動",
|
||||
"prefs.graphics_card_missing": "保存されたグラフィックスカードが利用できないため、自動選択を使用します。",
|
||||
"prefs.graphics_card_restart": "SolidCraft の再起動後に有効になります。WGPU_ADAPTER_NAME がこの選択より優先されます。",
|
||||
"prefs.graphics_card_unused": "保存したグラフィックスカードはこのウィンドウでは使われていません。使用中のカードは「ヘルプ › SolidCraft について」とステータス行に表示されます。自動を試すか、カード名の一意な部分を WGPU_ADAPTER_NAME に設定してください。",
|
||||
"prefs.graphics_note": "速度と滑らかさのバランスを調整します。各選択肢の効果をサンプルで確認できます。",
|
||||
"prefs.graphics_presets_note": "プリセットは以下の設定をまとめて変更します。",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out": "ズームアウト時に拘束グリフを隠す",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out_note": "スケッチを十分にズームアウトすると、拘束グリフは表示されず画面を散らかしません。オフ: ズームに関係なく固定の画面サイズのままです。",
|
||||
"prefs.history": "履歴",
|
||||
"prefs.history_origin_bodies": "原点とボディを先頭に表示",
|
||||
"prefs.history_origin_bodies_note": "左側またはブラウザー下の履歴の先頭に、アクティブなコンポーネントのボディフォルダーと原点を、ブラウザーと同じ表示切り替えとメニュー付きで表示します。下部の履歴は変わりません。",
|
||||
@@ -1878,6 +2181,8 @@
|
||||
"prefs.history_sketches_note": "スケッチ:「フィーチャーの下」では、左側の履歴に名前が表示される幅があるとき、スケッチをそれから作成した最初のフィーチャーの下に 1 段字下げして表示します。下部のタイムラインは常に作成順です。",
|
||||
"prefs.history_sketches_under_feature": "フィーチャーの下",
|
||||
"prefs.hold_stop_snapping": "押している間スナップを解除",
|
||||
"prefs.home_fit_size": "ホームと全体表示の大きさ",
|
||||
"prefs.home_fit_size_note": "ホーム、全体表示、開いたデザイン、ナビゲーターでの視点変更がモデルを画面に収めるときに、モデルがビューに占める割合。下の設定のオン・オフにかかわらず適用されます。100 %: パネル、コンパス、ナビゲーションバーの間のビューをいっぱいに使います。",
|
||||
"prefs.icons_only": "アイコンのみ",
|
||||
"prefs.imported_file": "読み込んだファイル",
|
||||
"prefs.in_browser": "ブラウザー内",
|
||||
@@ -1886,13 +2191,20 @@
|
||||
"prefs.interface_language": "表示言語",
|
||||
"prefs.interface_note": "SolidCraft の外観と各パネルの配置。",
|
||||
"prefs.interval_minutes": "{n} 分",
|
||||
"prefs.invert_navigator_arrows": "ビューキューブの回転矢印を反転",
|
||||
"prefs.invert_navigator_arrows_note": "キューブの周りの矢印が、矢印の指す方向にカメラを回します(Fusion や Inventor と同じ動き):左の矢印は右を指し、カメラを右に振ります。オフ: 矢印は、そのある面の方へキューブを回すため、左の矢印はカメラを左に振ります。カーブしたロール矢印は影響を受けません。",
|
||||
"prefs.keep_work_on_tab_switch": "デザインを切り替えてもダイアログとツールを開いたままにする",
|
||||
"prefs.keep_work_on_tab_switch_note": "各デザインのタブが、開いているダイアログまたはツール(選択や入力した内容を含む)とツールバーのタブを保持します。デザインに戻ると元のまま表示されます。オフ: デザインを切り替えるとそれらはキャンセルされ、モデル タブが表示されます。",
|
||||
"prefs.labels": "ラベル",
|
||||
"prefs.language_system": "システム",
|
||||
"prefs.layout": "レイアウト",
|
||||
"prefs.layout_note": "コンパクトではパネルをウィンドウの端に固定します。ブラウザーの半透明表示はフローティングで使用できます。アシスタントの配置はアシスタントページで変更します。",
|
||||
"prefs.left": "左",
|
||||
"prefs.left_click": "左クリック",
|
||||
"prefs.line_drag_draws_one": "押してドラッグすると線を 1 本描く",
|
||||
"prefs.line_drag_draws_one_note": "線ツールで押してドラッグし、離すと、押した位置から離した位置まで線を 1 本描いてそこで終わります。クリックでは従来どおり連続した線を描きます。オフ: ドラッグはクリックと同じく、離した位置に点を置きます。",
|
||||
"prefs.line_hover_tangent_arc": "線の最後の点で止めると接線円弧に切り替える",
|
||||
"prefs.line_hover_tangent_arc_note": "線ツールで線分を描いたあと、連続線の最後の点から一度離れて戻り、その点の上でポインターを止めると、次のクリックで接線円弧の終点を指定します。同じ操作で線に戻ります。オフ: 止めても何も起こりません。",
|
||||
"prefs.linked_designs": "リンクされたデザイン",
|
||||
"prefs.live_input": "現在の入力",
|
||||
"prefs.live_preview": "ライブプレビュー",
|
||||
@@ -1906,6 +2218,9 @@
|
||||
"prefs.max_file_size_step": "STEP・インポートファイル",
|
||||
"prefs.max_file_size_web": "ウェブ版で開けるのは STEP・インポートファイルが 512 MB、デザインが 256 MB までです。ブラウザーのタブはそれ以上のファイルを保持できません。デスクトップ版では上限を上げられます。",
|
||||
"prefs.megabytes": "MB",
|
||||
"prefs.menu_grid": "大きなアイコン",
|
||||
"prefs.menu_list": "リスト",
|
||||
"prefs.menus": "メニュー",
|
||||
"prefs.minutes": "分",
|
||||
"prefs.minutes_suffix": " min",
|
||||
"prefs.mouse": "マウスとトラックパッド",
|
||||
@@ -1913,6 +2228,8 @@
|
||||
"prefs.mouse_mapping": "マウスの割り当て",
|
||||
"prefs.navigation": "ナビゲーション",
|
||||
"prefs.navigation_note": "マウス、トラックパッド、3Dマウスによるビューの操作。",
|
||||
"prefs.navigator_fit": "ナビゲーターでの視点変更後にモデルを全体表示",
|
||||
"prefs.navigator_fit_note": "キューブの面・角・矢印やギズモの軸をクリックすると、どの方向からでも全体が収まる一定の距離(外接球)からモデルの中心を見ます。オンの間はホームビューも同じズームと中心を使うため、その後に選んだ視点は向きだけが変わります。オフ: 視点はその場で回転し、注視点とズームを保ちます。",
|
||||
"prefs.network_host_remove": "削除",
|
||||
"prefs.network_locations": "デザイン内のネットワーク上の場所を許可",
|
||||
"prefs.network_locations_note": "オフ: 別のコンピューター (\\\\server\\share) にあるデザインのリンク先ファイルは、ここに表示されたサーバー、または確認時に許可したサーバーからのみ開きます。",
|
||||
@@ -1925,10 +2242,16 @@
|
||||
"prefs.origin_plane_names": "原点平面の名前",
|
||||
"prefs.origin_plane_names_note": "ブラウザー、ダイアログ、一覧に表示される名前です。{top} は XY、{front} は XZ、{right} は YZ です (Z が上)。コマンド、スクリプト、保存されたデザインでは XY、XZ、YZ のままです。",
|
||||
"prefs.overall_speed": "全体の速度",
|
||||
"prefs.parameter_list_rows": "パラメーター一覧の行数",
|
||||
"prefs.parameter_list_rows_tip": "空の値フィールドで下矢印を押すと、お気に入りを先頭にパラメーターをこの数まで一覧表示します。少なくすると大きな設計でも一覧が軽くなります。",
|
||||
"prefs.persistent_ribbon_pressed": "有効なリボンコマンドを強調表示",
|
||||
"prefs.persistent_ribbon_pressed_help": "効果が有効な間、リボンのコマンドを強調表示します。無効にすると、従来の中立的な表示とコマンドのヘルプを保持します。",
|
||||
"prefs.perspective_fov": "画角",
|
||||
"prefs.placement": "配置",
|
||||
"prefs.prefer_free_sketch_points": "スケッチ点が重なったときは移動可能な点を優先する",
|
||||
"prefs.preview_choices": "選択した設定のプレビュー",
|
||||
"prefs.print_face_highlight": "造形面の強調",
|
||||
"prefs.print_face_highlight_tip": "ビューでボディの造形面を色付けし輪郭を描く強さ。0 % で強調しません。",
|
||||
"prefs.profile_active": "使用中のプロファイル",
|
||||
"prefs.profile_applied": "プロファイルを適用しました。",
|
||||
"prefs.profile_changed": "プロファイルの保存後に設定が変更されています。「保存」でプロファイルに反映されます。",
|
||||
@@ -1950,9 +2273,13 @@
|
||||
"prefs.quality_fastest": "最速",
|
||||
"prefs.quality_slowest": "最も低速",
|
||||
"prefs.quality_smoother": "より滑らか",
|
||||
"prefs.quick_measure": "ビューの隅にクイック測定",
|
||||
"prefs.quick_measure_note": "選択したものの寸法をビューの右下、履歴の上に表示します: エッジの長さ(円形のものは Ø と R)、面の面積、点の位置、2 つの項目の距離と角度、複数のエッジや面の合計。クリックでコピーします。",
|
||||
"prefs.render_previous_geometry_budget": "レンダープレビューで以前のジオメトリ予算を使用",
|
||||
"prefs.render_previous_geometry_budget_help": "デバイスに基づく予算の代わりに、以前の固定ジオメトリ上限(64ビットデスクトップでは512 MiB、その他では128 MiB)に戻します。",
|
||||
"prefs.reports_saved": "{n} 件保存済み",
|
||||
"prefs.ribbon_click_ends_tool": "実行中のツールのボタンをクリックすると終了する",
|
||||
"prefs.ribbon_click_ends_tool_note": "使用中のスケッチツールの点灯したリボンボタンをクリックするとツールが終了し、ビューのクリックで再び選択できます。オフ: クリックするとツールが最初から開始されます。",
|
||||
"prefs.ribbon_reveal": "検索結果をリボンに表示",
|
||||
"prefs.ribbon_reveal_note": "コマンド検索で結果にポインターを合わせると、そのコマンドがリボンのどこにあるか(タブ、ボタン、またはパネルのドロップダウン内の行)を表示します。検索から開始したコマンドはそこで点滅し、ドロップダウンから実行中のコマンドはそのパネルに印が付きます。",
|
||||
"prefs.right_click": "右クリック",
|
||||
@@ -1963,6 +2290,8 @@
|
||||
"prefs.search_empty": "一致する設定がありません",
|
||||
"prefs.select": "選択",
|
||||
"prefs.select_one_item": "項目を 1 つ選択",
|
||||
"prefs.select_other_hidden": "「他を選択」で非表示のジオメトリを選択",
|
||||
"prefs.select_other_hidden_help": "オン: ポインター付近の非表示のボディやスケッチ、遮られたエッジを含めます。オフ: ポインター直下の表示中のジオメトリだけを元のリストに表示します。",
|
||||
"prefs.selecting": "選択",
|
||||
"prefs.shift": "Shift",
|
||||
"prefs.shift_add_ctrl_toggle": "Shift は追加のみ、Ctrl / Cmd は選択を切り替え",
|
||||
@@ -1974,11 +2303,18 @@
|
||||
"prefs.sketch_align_points_note": "描画中、点が一つのスケッチ点と水平に、別の点と垂直に同時に揃い、点線のガイドが表示されます。クリックすると両方の整列が保持されます。オフ: 直前の点にのみ、一度に一方向だけ揃えます。",
|
||||
"prefs.sketch_conflict_colour": "競合するジオメトリを競合色で表示",
|
||||
"prefs.sketch_conflict_colour_note": "スケッチの拘束が競合している間、満たされない拘束のグリフや寸法だけでなく、その拘束が保持する曲線と点も競合色で描画します。オフ: 通常の色のままです。",
|
||||
"prefs.sketch_construction_lines": "拡張補助直線ツール",
|
||||
"prefs.sketch_exit_view": "スケッチ終了時のビュー",
|
||||
"prefs.sketch_exit_view.keep": "現在のビューを維持",
|
||||
"prefs.sketch_exit_view.previous": "前のビューに戻る",
|
||||
"prefs.sketch_exit_view.unless_rotated": "回転していなければ戻る",
|
||||
"prefs.sketch_exit_view_note": "「スケッチを終了」、キャンセル、Esc の 2 回押しの後にビューが移る先です。",
|
||||
"prefs.sketch_face_activates_part": "部品の面にスケッチするとその部品をアクティブにする",
|
||||
"prefs.sketch_face_activates_part_note": "別のコンポーネントのボディの面で始めたスケッチは、先にそのコンポーネントをアクティブにし、スケッチはそのコンポーネントに属してブラウザでその部品の下に表示されます。部品はその後もアクティブのままです。オフ:スケッチはアクティブなコンポーネントに属します。",
|
||||
"prefs.sketch_open_look_at": "スケッチを開いたときに正対させる",
|
||||
"prefs.sketch_open_look_at_note": "オフ: スケッチの作成や編集でビューを動かしません。必要なときは「正面視」でスケッチに正対します。",
|
||||
"prefs.sketch_recent_snap": "最近使った中心と中点へ自動スナップ",
|
||||
"prefs.sketch_recent_snap_note": "作図中、直前の2つの円の中心または直線辺の中点のガイドが交わる位置にカーソルをスナップします。オフ: ガイドは表示のみで、カーソルは移動しません。",
|
||||
"prefs.sketch_selection": "スケッチと選択",
|
||||
"prefs.sketch_selection_heading": "スケッチと選択",
|
||||
"prefs.sketch_selection_note": "スケッチのスナップとクリックによる選択。",
|
||||
@@ -1988,6 +2324,8 @@
|
||||
"prefs.sketch_tab_always_note": "スケッチを開いていないときも、スケッチ タブをリボンのモデルのすぐ後に表示します。そこにある作図ツールは、選択した平面または面に、なければ次に選ぶ平面にスケッチを開始し、そのスケッチでツールをすぐ使える状態にします。",
|
||||
"prefs.sketch_tracking_guides": "中心・中点の整列ガイド",
|
||||
"prefs.sketch_tracking_guides_note": "円の中心や直線辺の中点にカーソルを合わせ、水平・垂直に移動すると一時的な点線ガイドを表示します。",
|
||||
"prefs.sketch_tracking_points": "作図中は端点と角からも整列ガイド",
|
||||
"prefs.sketch_tracking_points_note": "作図ツールが点を待っている間、線や円弧の端点、長方形の角、独立した点にカーソルを合わせると、中心や中点と同じ一時的な点線ガイドを表示します。オフ: 中心と中点のみ。",
|
||||
"prefs.sketching": "スケッチ",
|
||||
"prefs.snap_drawing_note": "スケッチの描画中または点のドラッグ中に使用します。",
|
||||
"prefs.source": "入力元",
|
||||
@@ -2004,6 +2342,24 @@
|
||||
"prefs.status_error": "エラー",
|
||||
"prefs.status_selected": "選択中",
|
||||
"prefs.status_warning": "警告",
|
||||
"prefs.structure.appearance": "外観",
|
||||
"prefs.structure.appearance_note": "色、文字、アクセシビリティ。",
|
||||
"prefs.structure.in_profile": "プロファイルに保存",
|
||||
"prefs.structure.layout": "レイアウト",
|
||||
"prefs.structure.layout_note": "ウィンドウ内の配置。",
|
||||
"prefs.structure.look": "表示",
|
||||
"prefs.structure.measure_pointer": "計測とポインター",
|
||||
"prefs.structure.mouse3d": "3Dマウス",
|
||||
"prefs.structure.mouse3d_note": "SpaceMouse と SpaceNavigator。",
|
||||
"prefs.structure.navigation_note": "マウスとトラックパッド。3Dマウスは専用ページにあります。",
|
||||
"prefs.structure.profile": "プロファイル",
|
||||
"prefs.structure.profile_edited": "保存後に変更あり",
|
||||
"prefs.structure.profile_hover": "設定プロファイルに保存されます",
|
||||
"prefs.structure.scale_percent": "{percent}%",
|
||||
"prefs.structure.sketch": "スケッチ",
|
||||
"prefs.structure.tools": "ツール",
|
||||
"prefs.structure.tools_note": "モデリングツールの動作。",
|
||||
"prefs.structure.work": "作業",
|
||||
"prefs.supersampling_brief": "大きく描画して縮小するため、非常に鮮明になりますが負荷も増えます。",
|
||||
"prefs.tab_accent_note": "アクセント色はアクティブなタブに従います",
|
||||
"prefs.theme_file": "テーマファイル",
|
||||
@@ -2015,6 +2371,16 @@
|
||||
"prefs.theme_follow_off": "オフ",
|
||||
"prefs.theme_follow_stop": "追従を停止",
|
||||
"prefs.theme_import_hint": "クリックしてテーマファイルを選ぶか、ここにドロップするか、テーマをコピーした状態で Ctrl+V(Mac では Cmd+V)を押します",
|
||||
"prefs.theme_option_opacity": "不透明度",
|
||||
"prefs.theme_option_opacity_help": "フローティングパネルの不透明度を調整します。ビューポートの色に重なっても文字が読めるように下限が適用されます。",
|
||||
"prefs.theme_option_tab_colours": "タブの色",
|
||||
"prefs.theme_option_tab_colours_help": "リボンタブごとにテーマのパネルとビューポートの色を使用します。",
|
||||
"prefs.theme_option_tab_fade_ms": "タブの切り替え",
|
||||
"prefs.theme_option_tab_fade_ms_help": "タブの切り替え時にパネルとビューポートの色を徐々に変えます。0で即座に切り替えます。",
|
||||
"prefs.theme_options_badge": "オプション",
|
||||
"prefs.theme_options_more": "その他 · {count}",
|
||||
"prefs.theme_options_reset": "リセット",
|
||||
"prefs.theme_options_unavailable": "このデバイスでは利用できません",
|
||||
"prefs.theme_paste": "テーマを貼り付け",
|
||||
"prefs.theme_paste_none": "クリップボードに SolidCraft のテーマがありません",
|
||||
"prefs.timeline_half_hour": "−30 分",
|
||||
@@ -2036,13 +2402,23 @@
|
||||
"prefs.under_cursor": "カーソル下",
|
||||
"prefs.units_precision": "単位と精度",
|
||||
"prefs.updates": "更新",
|
||||
"prefs.value_boxes_in_view": "ビューでハンドルの横に値を表示",
|
||||
"prefs.value_boxes_in_view_tip": "コマンドの値(距離、半径など)をモデル上のハンドルの横のボックスに表示します。オフにすると、値はコマンドウィンドウに入力します。選択後はそのウィンドウにキーボード入力が入り、モデルを覆うものはありません。",
|
||||
"prefs.view": "ビューの動作",
|
||||
"prefs.view_confirm_corner": "ビューの隅に OK とキャンセル",
|
||||
"prefs.view_confirm_corner_note": "ダイアログまたはスケッチを開いている間、ビュー右上のチェックとバツが、ダイアログの OK とキャンセルと同じ操作を行うか、スケッチを終了またはキャンセルします。ビューナビゲーターはその下に移動します。",
|
||||
"prefs.viewport": "ビューポート",
|
||||
"prefs.viewport_analysis_status": "ビューポートの解析状態を表示",
|
||||
"prefs.viewport_analysis_status_help": "有効な解析をビューポートの上部に表示し、各項目から凡例を開きます。Esc で最新の解析を解除します。無効にすると隅の凡例と従来の Esc 動作に戻ります。",
|
||||
"prefs.viewport_background": "背景",
|
||||
"prefs.viewport_background_colour": "色",
|
||||
"prefs.viewport_background_theme": "テーマのグラデーション",
|
||||
"prefs.viewport_section_status": "ビューポートの断面状態を表示",
|
||||
"prefs.viewport_section_status_help": "ビューポートに断面設定を表示します。Escape または有効なリボンボタンで断面を解除します。無効にすると従来の断面操作を維持します。",
|
||||
"prefs.viewport_status_details": "ビューポートのライブ詳細",
|
||||
"prefs.viewport_status_details_help": "標準の詳細カードで、実行中の解析と断面の設定を編集します。無効にすると、読み取り専用の解析凡例と断面ダイアログに戻ります。",
|
||||
"prefs.viewport_status_summary": "ビューポートの状態項目をまとめる",
|
||||
"prefs.viewport_status_summary_help": "3 個以上の状態項目を 1 つのサマリーバッジにまとめます。無効にすると、すべての項目を従来の行に表示します。",
|
||||
"prefs.wheel": "ホイール",
|
||||
"prefs.wheel_trackpad": "ホイールとトラックパッド",
|
||||
"prefs.workspace": "ワークスペース",
|
||||
@@ -2052,6 +2428,10 @@
|
||||
"properties.title": "プロパティ: {name}",
|
||||
"recovery.days_ago": "{count}日前",
|
||||
"recovery.detail": "{file} · {features}フィーチャー · 自動保存: {when}",
|
||||
"recovery.discard_all": "すべて破棄",
|
||||
"recovery.discard_all_detail": "この操作は元に戻せません。",
|
||||
"recovery.discard_all_title": "{count} 件の自動保存を破棄しますか?",
|
||||
"recovery.discard_all_title_one": "1 件の自動保存を破棄しますか?",
|
||||
"recovery.hours_ago": "{count}時間前",
|
||||
"recovery.just_now": "たった今",
|
||||
"recovery.min_ago": "{count}分前",
|
||||
@@ -2917,7 +3297,9 @@
|
||||
"render.output_ready": "レンダーの準備完了",
|
||||
"render.output_run_check": "チェックを実行",
|
||||
"render.output_size_limit": "{method}:各辺 {dimension} px、合計 {pixels} ピクセルまで。対応する最大サイズ:{width} × {height}。",
|
||||
"render.output_size_method_profile": "{width} × {height} をレンダリングするには、{method} と CPUリソースプロファイル「{profile}」を選ぶか、より小さいサイズを選んでください。",
|
||||
"render.output_size_ok": "サイズOK · {width} × {height} px",
|
||||
"render.output_size_profile": "{width} × {height} をレンダリングするには、CPUリソースプロファイル「{profile}」を選ぶか、より小さいサイズを選んでください。",
|
||||
"render.output_swap_orientation": "幅と高さを交換",
|
||||
"render.output_tools_inspector": "サイズと形式は出力インスペクターで編集してください。",
|
||||
"render.output_view_image": "画像を表示",
|
||||
@@ -3130,6 +3512,7 @@
|
||||
"render.size_custom": "カスタム…",
|
||||
"render.size_full_hd": "フルHD",
|
||||
"render.size_hd": "HD",
|
||||
"render.size_needs_profile": "{size}・「{profile}」が必要",
|
||||
"render.size_presets": "サイズプリセット",
|
||||
"render.size_presets_pending": "出力エディターとともに追加予定",
|
||||
"render.size_preview": "プレビュー",
|
||||
@@ -3417,6 +3800,24 @@
|
||||
"sheet.flange_type_contour": "輪郭",
|
||||
"sheet.flange_type_edge": "エッジ",
|
||||
"sheet.no_body": "板金ボディがありません。フランジ > Base で作成するか、板金に変換でプレートを板金に変換してください(広い平面を選択)。",
|
||||
"sheet.personal_rules.confirm_delete": "削除を確認",
|
||||
"sheet.personal_rules.delete": "削除",
|
||||
"sheet.personal_rules.delete_prompt": "この個人用ルールを削除しますか?デザインに既にあるルールは変更されません。",
|
||||
"sheet.personal_rules.full": "個人用ライブラリには既に64個のルールがあります。",
|
||||
"sheet.personal_rules.invalid_name": "改行や制御文字を含まない短い名前を入力してください。",
|
||||
"sheet.personal_rules.invalid_values": "ルールの値をすべて入力してください。各値はこのデザインで計算でき、板厚は正の値、K係数は0〜1である必要があります。",
|
||||
"sheet.personal_rules.missing": "選択した個人用ルールは利用できなくなりました。",
|
||||
"sheet.personal_rules.name": "ルール名",
|
||||
"sheet.personal_rules.name_exists": "同じ名前の個人用ルールが既にあります。別の名前を指定してください。",
|
||||
"sheet.personal_rules.name_hint": "一意の名前",
|
||||
"sheet.personal_rules.overwrite": "選択した個人用ルールの変更を保存",
|
||||
"sheet.personal_rules.rename": "名前を変更",
|
||||
"sheet.personal_rules.rule": "個人用ルール",
|
||||
"sheet.personal_rules.save": "新規保存",
|
||||
"sheet.personal_rules.scope": "すべてのデザインで使えるようにプロファイルに保存します。",
|
||||
"sheet.personal_rules.select": "ルールを選択",
|
||||
"sheet.personal_rules.title": "個人用ルール",
|
||||
"sheet.personal_rules.unsupported": "このルールには、このバージョンで使用できない値が含まれています。",
|
||||
"shortcut.json_error": "パラメータはJSON形式で指定してください: {error}",
|
||||
"shortcut.no_command": "コマンド`{id}`がありません。JSONの前のテキストはコマンドIDである必要があります",
|
||||
"shortcut.pin": "Sボックスの先頭にピン留め",
|
||||
@@ -3453,8 +3854,10 @@
|
||||
"sketch_text.align_right": "右",
|
||||
"sketch_text.bold": "太字",
|
||||
"sketch_text.builtin_font": "{family}(内蔵)",
|
||||
"sketch_text.formula": "= で始めるとパラメーターから文字列を組み立てられます: ='W' + number(Width)",
|
||||
"sketch_text.italic": "斜体",
|
||||
"sketch_text.loading_fonts": "インストール済みフォントを検索中…",
|
||||
"sketch_text.no_bold": "組み込みフォントには太字がありません: インストール済みのフォントを選択してください",
|
||||
"sketch_text.on_path": "文字はパスに沿います: 位置は曲線で決まります",
|
||||
"sketch_text.path_clear": "文字を曲線から外す",
|
||||
"sketch_text.path_hint": "文字が沿うスケッチの曲線: ここをクリックしてから曲線をクリック",
|
||||
@@ -3593,6 +3996,8 @@
|
||||
"ui.3d_mouse_section": "3Dマウス",
|
||||
"ui.3d_mouse_show_in_view": "3Dビューに3Dマウスを表示",
|
||||
"ui.3d_mouse_show_in_view_tip": "左下に3Dマウスの絵を表示し、操作に合わせて動かします。",
|
||||
"ui.3d_mouse_sketch_orbit": "3D マウスでスケッチを回転",
|
||||
"ui.3d_mouse_sketch_orbit_tip": "スケッチを開いて正面から見ているときも、マウスと同じように 3D マウスでビューを回転します。オフ: ビューを傾けるまで、スケッチのパンとズームのみ行います。",
|
||||
"ui.3d_mouse_skip": "このデバイスではできません",
|
||||
"ui.3d_mouse_skip_tip": "この動きを両方向とも飛ばし、キャリブレーションから外します。",
|
||||
"ui.3d_mouse_speed": "3D マウス速度",
|
||||
@@ -3621,6 +4026,8 @@
|
||||
"ui.3d_mouse_step_twist_counterclockwise": "キャップを反時計回りにひねって保持し、離してください。",
|
||||
"ui.3d_mouse_switch_cap": "センターに戻るタイプとしてキャリブレーション",
|
||||
"ui.3d_mouse_switch_trackball": "トラックボールとしてキャリブレーション",
|
||||
"ui.3d_mouse_use_direct": "直接ドライバーを使用",
|
||||
"ui.3d_mouse_use_direct_tip": "spacenavd を経由せず、3Dマウスを直接 (hidraw) 読み取ります。",
|
||||
"ui.3d_mouse_view_axis": "ビューの軸",
|
||||
"ui.3d_mouse_view_off": "オフ",
|
||||
"ui.3d_mouse_view_off_tip": "3D マウスのドライバーのプロファイルがこの軸をオフにしているため、この軸の動きではビューは動きません。ここで他の軸の動きを選ぶと 2 つが入れ替わり、その動きではビューが動かなくなります。",
|
||||
@@ -3659,6 +4066,7 @@
|
||||
"ui.agent_chat_auth_terminal": "ターミナルでこれを実行してから、もう一度「接続」を押してください:",
|
||||
"ui.agent_chat_auth_title": "エージェントにサインイン",
|
||||
"ui.agent_chat_cancel": "キャンセル",
|
||||
"ui.agent_chat_cannot_start": "インストールされていますが、起動しません: {error}",
|
||||
"ui.agent_chat_changes": "{n} 件の変更(元に戻すは1回)",
|
||||
"ui.agent_chat_changes_n": "{n} 件の変更",
|
||||
"ui.agent_chat_changes_of": "変更 {n}/{limit}",
|
||||
@@ -3751,9 +4159,12 @@
|
||||
"ui.agent_chat_queued_stopped": "待機中(停止済み・未送信)",
|
||||
"ui.agent_chat_refresh": "再検索",
|
||||
"ui.agent_chat_refused": "エージェントには許可されていません: {reason}",
|
||||
"ui.agent_chat_reinstall": "{agent} はインストールされています ({program}) が、SolidCraft が確認したときに起動しませんでした: {error}\nインストールが不完全か、別の種類のコンピューター用の可能性があります。`{install}` で再インストールし、ターミナルでバージョンが表示されることを確認してから、再検索を押してください。",
|
||||
"ui.agent_chat_remove": "待機から削除",
|
||||
"ui.agent_chat_remove_file": "このメッセージから外す",
|
||||
"ui.agent_chat_remove_imported": "このメッセージから外します。パーツはデザインに残ります (元に戻すで削除できます)",
|
||||
"ui.agent_chat_reply_cut_off": "応答が終わる前に長さの上限に達したため、不完全な可能性があります。続けるか、もっと短く答えるようエージェントに頼んでください。",
|
||||
"ui.agent_chat_reply_declined": "モデルはこのメッセージへの回答を断りました。",
|
||||
"ui.agent_chat_retry": "再試行",
|
||||
"ui.agent_chat_right": "右",
|
||||
"ui.agent_chat_save": "保存",
|
||||
@@ -3812,12 +4223,17 @@
|
||||
"ui.ai_copy_suffix": "コピー",
|
||||
"ui.ai_custom_url": "カスタム URL",
|
||||
"ui.ai_default": "既定",
|
||||
"ui.ai_edit": "編集",
|
||||
"ui.ai_edit_agent_title": "エージェントを編集",
|
||||
"ui.ai_edit_gone": "このエージェントは削除されたため、保存するものはありません。",
|
||||
"ui.ai_edit_tip": "このエージェントの名前、コマンド、エンドポイントを変更します。保存済みのキーは表示されません。",
|
||||
"ui.ai_http_busy": "エンドポイントが混雑しているか上限に達しています。後で再試行してください",
|
||||
"ui.ai_http_key": "エンドポイントがキーを拒否しました。「環境設定 > AI」で確認してください",
|
||||
"ui.ai_http_not_found": "エンドポイントまたはモデルが見つかりません。ベース URL とモデル名を確認してください",
|
||||
"ui.ai_http_too_large": "会話がこのエンドポイントには大きすぎます。新しいチャットを始めてください",
|
||||
"ui.ai_key": "API キー",
|
||||
"ui.ai_key_hint": "任意。システムのキーチェーンに保存",
|
||||
"ui.ai_key_keep_hint": "空のままにすると保存済みのキーを使い続けます",
|
||||
"ui.ai_key_needs_https": "キーは HTTPS 経由、またはこのコンピューター宛てにのみ送信されます。",
|
||||
"ui.ai_key_note": "システムのキーチェーンに保存され、SolidCraft の設定には保存されません。ローカルサーバーの場合は空欄のままにします。",
|
||||
"ui.ai_keychain_error": "システムのキーチェーンが拒否しました: {error}",
|
||||
@@ -3844,11 +4260,15 @@
|
||||
"ui.ai_permissions": "権限",
|
||||
"ui.ai_preset": "プリセット",
|
||||
"ui.ai_protocol": "プロトコル",
|
||||
"ui.ai_reasoning_effort": "推論の強度",
|
||||
"ui.ai_reasoning_effort_field_hint": "空 = プロバイダーの既定値",
|
||||
"ui.ai_reasoning_effort_hint": "任意。エンドポイントに `reasoning_effort` として送信されます。許可される値はプロバイダーによって異なります(例: `low`、`high`、`max`)。ここで設定した値が SolidCraft に置き換えられることはありません。空のままなら何も送信されず、プロバイダーの既定値が使われます。",
|
||||
"ui.ai_remove": "削除",
|
||||
"ui.ai_request_timed_out": "モデルの応答に {seconds} 秒以上かかりました。このエンドポイントのリクエストのタイムアウトは、環境設定 › アシスタントで長くできます。",
|
||||
"ui.ai_request_timeout": "リクエストのタイムアウト",
|
||||
"ui.ai_request_timeout_hint": "このエンドポイントへのモデルリクエスト1回にかけられる時間です(30秒〜1時間)。遅いローカルモデルでは長くしてください。",
|
||||
"ui.ai_reset": "リセット",
|
||||
"ui.ai_save": "保存",
|
||||
"ui.ai_settings": "AI 設定…",
|
||||
"ui.ai_show_features": "AI 機能を表示",
|
||||
"ui.ai_show_features_note": "エージェントチャット: 普段使っているコーディングエージェント、または選んだモデルのエンドポイントが、開いているデザインを操作するパネルです。オフ: AI ボタン、ショートカット、メニュー項目、パネルは表示されず、検索も起動も行いません。",
|
||||
@@ -3937,6 +4357,7 @@
|
||||
"ui.circle": "円",
|
||||
"ui.circular_pattern": "円形パターン",
|
||||
"ui.clear": "クリア",
|
||||
"ui.clear_print_face": "造形面を解除",
|
||||
"ui.clear_recent": "最近使った項目をクリア",
|
||||
"ui.clear_the_selection": "選択をクリア",
|
||||
"ui.click_selects_whole_bodies": "クリックでボディ全体を選択",
|
||||
@@ -3971,6 +4392,15 @@
|
||||
"ui.constant": "一定",
|
||||
"ui.constraints_conflict": "拘束が競合しています",
|
||||
"ui.construction": "コンストラクション",
|
||||
"ui.construction.angle_hint": "補助直線: 点をクリックし、角度を入力するか方向を選択",
|
||||
"ui.construction.bisector_hint": "二等分線: 交差する2直線を選び、必要な解を選択",
|
||||
"ui.construction.common_hint": "共通接線: 2つの円/円弧を選び、必要な解を選択",
|
||||
"ui.construction.contact_hint": "接線: 円/円弧または開いたスプライン/円錐曲線を選び、接点を選択 (自由曲線は端点のみ)",
|
||||
"ui.construction.external_hint": "接線: 円または円弧、外部点、必要な解の順に選択",
|
||||
"ui.construction.free_hint": "補助直線: 2点をクリック。右クリックで最初から",
|
||||
"ui.construction.point_hint": "補助直線: 通過点をクリック",
|
||||
"ui.construction.reference_hint": "補助直線: 直線、点の順に選択。右クリックで参照を変更",
|
||||
"ui.construction.ribbon_label": "補助線",
|
||||
"ui.context_menu": "コンテキスト メニュー",
|
||||
"ui.continuity_g0": "G0 折れ",
|
||||
"ui.continuity_g1": "G1 接線",
|
||||
@@ -3998,6 +4428,7 @@
|
||||
"ui.dark": "ダーク",
|
||||
"ui.default_modelling_orientation": "モデリングのデフォルト方向",
|
||||
"ui.delete": "削除",
|
||||
"ui.delete_select_first": "先に削除するものを選択してください: フィーチャ、ボディ、コンポーネント、スケッチ ジオメトリ",
|
||||
"ui.depth": "深さ",
|
||||
"ui.design": "デザイン",
|
||||
"ui.design_properties.author": "作成者",
|
||||
@@ -4012,6 +4443,40 @@
|
||||
"ui.design_properties.project": "プロジェクト",
|
||||
"ui.design_properties.revision": "リビジョン",
|
||||
"ui.design_saved": "{path} に保存しました",
|
||||
"ui.details_access_caption": "選択した方向から工具が各面に届くかどうかを表示します。",
|
||||
"ui.details_angle": "角度",
|
||||
"ui.details_continuity_caption": "選択した継ぎ目を編集します。他の継ぎ目の設定は変更されません。",
|
||||
"ui.details_continuity_stale": "以前の形状です。この継ぎ目を編集または画面にフィットするには、解析を再実行してください。",
|
||||
"ui.details_copy_list": "リストをコピー",
|
||||
"ui.details_curvature": "曲率許容差",
|
||||
"ui.details_curvature_caption": "面は局所的な曲率半径に応じて色分けされます。",
|
||||
"ui.details_direction": "工具方向",
|
||||
"ui.details_draft_caption": "面は抜き方向に対する角度に応じて色分けされます。",
|
||||
"ui.details_edit_seam": "継ぎ目を編集",
|
||||
"ui.details_fixture": "UIコンポーネントの表示例 — サンプルデータのみ",
|
||||
"ui.details_fixture_caption": "説明用の値を用いたUIコンポーネントの表示例です。モデルの解析結果ではありません。",
|
||||
"ui.details_fixture_problem": "問題を示す検出結果の例",
|
||||
"ui.details_fixture_readout": "測定値の例",
|
||||
"ui.details_flip": "反転",
|
||||
"ui.details_gap": "間隔",
|
||||
"ui.details_hatch": "切断面をハッチング",
|
||||
"ui.details_jump": "曲率の不連続",
|
||||
"ui.details_key": "凡例",
|
||||
"ui.details_offset": "オフセット",
|
||||
"ui.details_plane": "平面",
|
||||
"ui.details_pull": "抜き方向",
|
||||
"ui.details_radius": "半径",
|
||||
"ui.details_readout": "測定値",
|
||||
"ui.details_samples": "サンプル数",
|
||||
"ui.details_seam": "{body} · エッジ {edge}",
|
||||
"ui.details_settings": "設定",
|
||||
"ui.details_sharp_gap": "角が鋭い、または間隔あり",
|
||||
"ui.details_show_all": "すべて表示({count} 件)",
|
||||
"ui.details_smooth": "滑らか",
|
||||
"ui.details_stripes": "縞模様",
|
||||
"ui.details_target": "形状を画面にフィット",
|
||||
"ui.details_worst_seams": "連続性の悪い継ぎ目",
|
||||
"ui.details_zebra_caption": "反射した縞模様で、面のつながりの滑らかさを確認できます。",
|
||||
"ui.diameter": "直径",
|
||||
"ui.dimension": "寸法",
|
||||
"ui.direct_interaction": "ダイレクト操作",
|
||||
@@ -4056,6 +4521,7 @@
|
||||
"ui.edit_in_place_saved_elsewhere": "部品は別のファイルに保存されました。アセンブリは引き続き {name} にリンクしています",
|
||||
"ui.edit_in_place_wait": "デザインで実行中の処理が終わるまでお待ちください",
|
||||
"ui.edit_section_analysis": "断面解析を編集",
|
||||
"ui.edit_sketch_empty": "編集できるスケッチはありません",
|
||||
"ui.ellipse": "楕円",
|
||||
"ui.emboss_wrap_note": "サポートされる円柱に接する直交線のプロファイルは自動的に巻き付けられます。対象を選ぶには壁を選択してください。",
|
||||
"ui.end_radius": "終了半径",
|
||||
@@ -4066,12 +4532,15 @@
|
||||
"ui.equation_explicit": "陽関数",
|
||||
"ui.equation_form": "形式",
|
||||
"ui.equation_note": "変数は単位のない数値です。sin(t) はラジアンとして扱います。単位のない結果はデザインの単位になります。",
|
||||
"ui.equation_note_range": "変数は範囲と同じく長さです。長さのパラメータと組み合わせられます。sin() には長さで割って渡します。単位のない結果はデザインの単位になります。",
|
||||
"ui.equation_parametric": "パラメトリック",
|
||||
"ui.equation_variable_unit": "変数に範囲の単位を持たせる",
|
||||
"ui.equation_x_of_t": "x(t)",
|
||||
"ui.equation_y_of_t": "y(t)",
|
||||
"ui.equation_y_of_x": "y(x)",
|
||||
"ui.equivalent_radius": "等価半径",
|
||||
"ui.expand": "展開",
|
||||
"ui.explode_needs_two_components": "分解図はコンポーネント同士を引き離すため、デザインに 2 つ以上のコンポーネントが必要です(新規コンポーネント、デザインを挿入、またはボディからコンポーネントを作成)",
|
||||
"ui.exportDxf": "DXF をエクスポート…",
|
||||
"ui.export_ellipsis_keymap": "エクスポート…",
|
||||
"ui.export_keymap_tip": "ショートカット、Sボックスのお気に入り、ツールバー設定をファイルに保存",
|
||||
@@ -4240,12 +4709,14 @@
|
||||
"ui.joints": "ジョイント",
|
||||
"ui.keyboard_shortcuts": "キーボードショートカット",
|
||||
"ui.language": "言語",
|
||||
"ui.lasso_select": "投げ縄(フリーハンドで囲む:完全に内側にあるものを選択)",
|
||||
"ui.layout_compact": "コンパクト",
|
||||
"ui.layout_floating": "フローティング",
|
||||
"ui.length": "長さ",
|
||||
"ui.length_decimals": "長さの小数点以下の桁数",
|
||||
"ui.light": "ライト",
|
||||
"ui.line": "線分",
|
||||
"ui.line_arc_hint": "接線円弧: 円弧の終点をクリックします。線に戻るには最後の点で再び止めます。右クリックまたは Esc で終了します",
|
||||
"ui.link_copies": "同一のコピーをリンク",
|
||||
"ui.link_copies_keep": "そのまま",
|
||||
"ui.link_copies_link": "リンク",
|
||||
@@ -4334,6 +4805,7 @@
|
||||
"ui.part_size_shared": "パーツを再構築し、追加したフィーチャを置き換えます。このコンポーネントのすべての配置が更新されます。",
|
||||
"ui.paste": "貼り付け",
|
||||
"ui.path": "パス",
|
||||
"ui.pattern_object_type_tip": "ボディ: ビューまたはブラウザで選ぶ立体形状。それぞれがまるごとコピーされます。\nフィーチャー: 押し出しや穴など履歴のステップ。履歴で、またはそれが作った面で選びます。そのステップが繰り返されます。\nスケッチはどちらでもありません: 曲線はスケッチ内のパターンかミラーで繰り返すか、先に押し出してください。",
|
||||
"ui.pattern_on_path": "パス上のパターン",
|
||||
"ui.perforate_margin_default": "直径と同じ",
|
||||
"ui.perforate_pitch": "ピッチ",
|
||||
@@ -4360,12 +4832,17 @@
|
||||
"ui.plugins_skipped": "{count} 個のフォルダを読めませんでした。",
|
||||
"ui.plugins_version": "{version}",
|
||||
"ui.point": "点",
|
||||
"ui.point_cloud_add_filter": "フィルターを追加…",
|
||||
"ui.point_cloud_auto_range": "範囲を自動設定",
|
||||
"ui.point_cloud_color_by": "色の付け方",
|
||||
"ui.point_cloud_file_colors": "ファイルの色",
|
||||
"ui.point_cloud_filter_by": "フィルター",
|
||||
"ui.point_cloud_height_high": "最高の高さ",
|
||||
"ui.point_cloud_height_low": "最低の高さ",
|
||||
"ui.point_cloud_legend_filter": "上の凡例で表示・非表示を切り替え",
|
||||
"ui.point_cloud_no_file_colors": "ファイルに色情報がありません",
|
||||
"ui.point_cloud_pause": "一時停止",
|
||||
"ui.point_cloud_play": "再生",
|
||||
"ui.point_cloud_single_color": "単色",
|
||||
"ui.point_cloud_size": "点のサイズ",
|
||||
"ui.point_cloud_units": "ファイルの単位",
|
||||
@@ -4374,6 +4851,11 @@
|
||||
"ui.polygon": "ポリゴン",
|
||||
"ui.preferences": "環境設定",
|
||||
"ui.press_a_key": "キーを押してください…",
|
||||
"ui.print_face_cleared": "{body}: 造形面を解除しました",
|
||||
"ui.print_face_input": "造形面",
|
||||
"ui.print_face_one_body": "造形面はボディごとに選びます。変更するにはそのボディだけを送信してください",
|
||||
"ui.print_face_pick": "ソリッドボディの平面を1つ選択すると造形面になります",
|
||||
"ui.print_face_set": "{body}: 造形面を設定しました。スライサーへ送るとこの面を下にして置きます",
|
||||
"ui.profile": "プロファイル",
|
||||
"ui.profile_plane": "プロファイル平面",
|
||||
"ui.profiles": "プロファイル",
|
||||
@@ -4389,6 +4871,7 @@
|
||||
"ui.properties.inertia_y": "Iyx, Iyy, Iyz",
|
||||
"ui.properties.inertia_z": "Izx, Izy, Izz",
|
||||
"ui.properties.measuring": "測定中…",
|
||||
"ui.properties.measuring_bodies": "測定中… {total} 個中 {done} 個のボディ",
|
||||
"ui.properties.measuring_failed": "測定が完了する前に停止しました。",
|
||||
"ui.properties.principal_axis": "主軸 {number}",
|
||||
"ui.properties.principal_moments": "主慣性モーメント",
|
||||
@@ -4437,6 +4920,7 @@
|
||||
"ui.revolve": "回転",
|
||||
"ui.ribbon_exit": "終了",
|
||||
"ui.ribbon_labels": "リボンのアイコンの下にテキストを表示",
|
||||
"ui.ribbon_menus_skip_pinned": "ピン留めしたコマンドをドロップダウンメニューに表示しない",
|
||||
"ui.ribbon_pin_footer": "ピン留めしたコマンドはリボンに表示されます。行にポインターを合わせて、ピン留めや解除ができます。",
|
||||
"ui.ribbon_workspace": "ワークスペース",
|
||||
"ui.right": "右側面",
|
||||
@@ -4455,6 +4939,7 @@
|
||||
"ui.selectOther": "その他を選択…",
|
||||
"ui.selectTangentChain": "接線チェーンを選択",
|
||||
"ui.select_all": "すべて選択",
|
||||
"ui.select_components_by_face": "コンポーネントを選択(面をクリックするとそのコンポーネントが選択されます)",
|
||||
"ui.selection": "選択",
|
||||
"ui.selection_modifiers": "選択修飾キー",
|
||||
"ui.selection_shift_add_only": "Shift+クリックで追加のみ(解除なし)",
|
||||
@@ -4496,6 +4981,11 @@
|
||||
"ui.sketch_intersect_selection_filter": "選択フィルター",
|
||||
"ui.sketch_modifiers": "スケッチ修飾キー",
|
||||
"ui.sketch_project_geometry": "ジオメトリ",
|
||||
"ui.sketch_report.all_constrained": "すべて完全に拘束されています。",
|
||||
"ui.sketch_report.dof": "自由度",
|
||||
"ui.sketch_report.loose": "完全には拘束されていません",
|
||||
"ui.sketch_report.status": "状態",
|
||||
"ui.sketch_report.title": "スケッチ レポート",
|
||||
"ui.sketch_scale": "スケッチ尺度",
|
||||
"ui.sketches": "スケッチ",
|
||||
"ui.slice": "スライス",
|
||||
@@ -4600,10 +5090,19 @@
|
||||
"ui.view_centre": "ビュー中心",
|
||||
"ui.viewport_status_clear": "{name}をオフにする",
|
||||
"ui.viewport_status_clear_hint": "{name}をオフにする · Esc",
|
||||
"ui.viewport_status_edges": "{count} エッジ",
|
||||
"ui.viewport_status_from": "方向 {direction}",
|
||||
"ui.viewport_status_key": "{name}の凡例を表示",
|
||||
"ui.viewport_status_minimum_radius": "最小半径",
|
||||
"ui.viewport_status_pairs": "{count} 組",
|
||||
"ui.viewport_status_section_hatch": "{setting} · ハッチング",
|
||||
"ui.viewport_status_section_plane": "現在の平面",
|
||||
"ui.viewport_status_section_tilted": "傾斜 · {offset}",
|
||||
"ui.viewport_status_stripes": "縞 {count} 本",
|
||||
"ui.viewport_status_summary_clear": "すべて解除",
|
||||
"ui.viewport_status_summary_heading": "このビュー内",
|
||||
"ui.viewport_status_summary_label": "{name} と他 {count} 項目",
|
||||
"ui.viewport_status_summary_more": "+{count}",
|
||||
"ui.viewport_theme_follow": "テーマに従う",
|
||||
"ui.visual_shaded_hidden_edges": "隠線付きシェーディング",
|
||||
"ui.visual_shaded_with_edges": "エッジ付きシェーディング",
|
||||
@@ -4640,7 +5139,9 @@
|
||||
"update.button": "アップデート",
|
||||
"update.button_version": "{version} にアップデート",
|
||||
"update.check_automatically": "アップデートを自動的に確認",
|
||||
"update.check_for_updates": "アップデートを確認",
|
||||
"update.check_now": "今すぐ確認",
|
||||
"update.check_unavailable": "このインストールではアップデートを確認できません。",
|
||||
"update.checking": "確認中…",
|
||||
"update.copy": "コピー",
|
||||
"update.dmg_opened": "ディスクイメージを検証して開きました: SolidCraft をアプリケーションフォルダにドラッグして古いものを置き換え、SolidCraft を再起動してください。",
|
||||
|
||||
@@ -711,6 +711,8 @@
|
||||
"cmd.appearance_pick_up": "모양 가져오기",
|
||||
"cmd.appearance_replace": "모양 바꾸기",
|
||||
"cmd.assembly_bom": "자재 명세서",
|
||||
"cmd.assembly_mass_properties": "질량 특성",
|
||||
"cmd.body.print_face": "출력 바닥면",
|
||||
"cmd.body_rename": "바디 이름 변경",
|
||||
"cmd.browser_group": "새 그룹",
|
||||
"cmd.browser_move": "브라우저 항목 이동",
|
||||
@@ -958,6 +960,16 @@
|
||||
"cmd.sheet_refold": "다시 접기",
|
||||
"cmd.sheet_rules": "판금 규칙 목록",
|
||||
"cmd.sheet_unfold": "펼치기",
|
||||
"cmd.sketch.construction_line": "보조 직선",
|
||||
"cmd.sketch.construction_line.angle": "각도 지정 보조 직선",
|
||||
"cmd.sketch.construction_line.bisector": "각의 이등분선",
|
||||
"cmd.sketch.construction_line.horizontal": "수평 보조 직선",
|
||||
"cmd.sketch.construction_line.parallel": "평행 보조 직선",
|
||||
"cmd.sketch.construction_line.perpendicular": "직교 보조 직선",
|
||||
"cmd.sketch.construction_line.tangent_at": "곡선 위 점에서의 접선",
|
||||
"cmd.sketch.construction_line.tangent_external": "외부 점을 지나는 접선",
|
||||
"cmd.sketch.construction_line.tangent_two": "공통 접선",
|
||||
"cmd.sketch.construction_line.vertical": "수직 보조 직선",
|
||||
"cmd.sketch_arc_center_point": "중심점 호",
|
||||
"cmd.sketch_arc_tangent": "접선 호",
|
||||
"cmd.sketch_arc_three_point": "3점 호",
|
||||
@@ -1083,6 +1095,7 @@
|
||||
"cmd.view.render_browser": "렌더 브라우저",
|
||||
"cmd.view.render_dock": "렌더 도크 이동",
|
||||
"cmd.view.render_focus": "렌더 집중 보기",
|
||||
"cmd.view.status_details": "뷰포트 상태 상세 정보",
|
||||
"cmd.view.status_items": "뷰포트 상태 항목",
|
||||
"cmd.view_ambient_occlusion": "앰비언트 오클루전",
|
||||
"cmd.view_angle_readout": "뷰 각도",
|
||||
@@ -1150,6 +1163,7 @@
|
||||
"dialog.dimension_insert_hint": "다른 구동 치수를 두 번 클릭하여 이름 삽입",
|
||||
"dialog.dimension_name": "치수: {name}",
|
||||
"dialog.edit_title": "{title} 편집",
|
||||
"dialog.pattern_sketch_not_object": "바디나 피처를 선택하세요. 스케치는 둘 다 아닙니다. 곡선은 스케치 안의 패턴이나 대칭 복사로 반복하거나, 먼저 돌출하세요.",
|
||||
"dialog.select": "↖ 선택",
|
||||
"dialog.selected_count": "↖ {count}개 선택됨",
|
||||
"dialog.selection_guidance": "변경할 입력을 선택하세요. 선택한 객체를 클릭하면 선택이 해제되며, Ctrl/Cmd를 누른 채 클릭해도 전환됩니다. 미리 보기를 확인한 다음 확인을 누르세요.",
|
||||
@@ -1199,6 +1213,16 @@
|
||||
"help.mit": "MIT 라이선스",
|
||||
"help.notice": "NOTICE",
|
||||
"help.pointcloud.insert": "PLY, XYZ 또는 PTS 스캔을 모델 옆에 포인트 클라우드로 삽입합니다. 측정 데이터를 참고하여 모델링할 때 사용합니다.",
|
||||
"help.sketch.construction_line": "두 점을 지나는 무한 보조 직선을 만듭니다. 스케치 프로파일을 나누지 않고 작도할 수 있습니다.",
|
||||
"help.sketch.construction_line.angle": "스케치 X축을 기준으로 지정한 각도의 무한 보조 직선을 만듭니다. 점을 선택한 뒤 각도를 입력하거나 방향을 선택합니다.",
|
||||
"help.sketch.construction_line.bisector": "교차하는 두 스케치 직선을 선택한 뒤 두 각의 이등분선 중 하나를 선택합니다. 결과는 원본 직선의 편집을 따릅니다.",
|
||||
"help.sketch.construction_line.horizontal": "한 점을 지나는 무한 수평 보조 직선을 만듭니다. 나중에 편집해도 수평 구속이 유지됩니다.",
|
||||
"help.sketch.construction_line.parallel": "스케치 직선을 선택한 뒤 평행한 무한 보조 직선을 배치합니다. 다른 참조를 선택하려면 마우스 오른쪽 버튼을 클릭합니다.",
|
||||
"help.sketch.construction_line.perpendicular": "스케치 직선을 선택한 뒤 직교하는 무한 보조 직선을 배치합니다. 다른 참조를 선택하려면 마우스 오른쪽 버튼을 클릭합니다.",
|
||||
"help.sketch.construction_line.tangent_at": "원이나 원호 위의 점, 또는 열린 스플라인이나 원뿔 곡선의 끝점에 접선을 만듭니다. 곡선을 선택한 뒤 접점을 선택합니다.",
|
||||
"help.sketch.construction_line.tangent_external": "원 또는 원호, 외부 점, 접선 해를 차례로 선택합니다. 미리보기에는 그려진 원호 위의 접점만 표시됩니다.",
|
||||
"help.sketch.construction_line.tangent_two": "두 원 또는 원호를 선택한 뒤 미리보기에서 공통 접선을 선택합니다. 접점은 그려진 곡선 위에 있어야 합니다.",
|
||||
"help.sketch.construction_line.vertical": "한 점을 지나는 무한 수직 보조 직선을 만듭니다. 나중에 편집해도 수직 구속이 유지됩니다.",
|
||||
"help.sketch.equation_curve": "범위에 걸쳐 수식으로 곡선을 그립니다: x(t)와 y(t), 또는 y = f(x). 수식에 매개변수를 쓸 수 있으며 곡선이 그 값을 따라갑니다. 사인파, 나선, 기어 이의 인벌류트에 사용합니다.",
|
||||
"help.solid.chamfer": "선택한 모서리를 지정한 거리만큼 평평하게 깎습니다. 날카로운 모서리를 다듬거나 핀 또는 나사가 쉽게 들어가도록 할 때 사용합니다.",
|
||||
"help.solid.extrude": "스케치 프로파일을 지정한 거리만큼 3D로 밀어내 재료를 더하거나 제거합니다. 평면 윤곽을 블록, 보스 또는 포켓으로 만들 때 사용합니다.",
|
||||
@@ -1505,6 +1529,8 @@
|
||||
"prefs.bottom_centre": "하단 가운데",
|
||||
"prefs.bottom_right": "오른쪽 아래",
|
||||
"prefs.browser": "브라우저",
|
||||
"prefs.browser_eye_left": "표시 아이콘을 접기 화살표 옆에 표시",
|
||||
"prefs.browser_eye_left_note": "브라우저 행의 표시 아이콘을 행 오른쪽 끝의 열이 아니라 이전처럼 접기 화살표 옆에 표시합니다.",
|
||||
"prefs.built_in": "기본 제공",
|
||||
"prefs.button_left": "왼쪽 드래그",
|
||||
"prefs.button_middle": "가운데 드래그",
|
||||
@@ -1521,6 +1547,8 @@
|
||||
"prefs.ctrl_cmd": "Ctrl / Cmd",
|
||||
"prefs.curved_surfaces": "곡면",
|
||||
"prefs.curves": "곡면",
|
||||
"prefs.dark_parts_shading": "어두운 부품의 형태 유지",
|
||||
"prefs.dark_parts_shading_help": "선형 조명과 부드러운 하늘광으로 뷰를 음영 처리하여 어두운 면이 검게 뭉개지지 않고 그라데이션을 유지합니다",
|
||||
"prefs.dead_zone_note": "빗금 친 영역이 데드존입니다. 그 안의 움직임은 무시됩니다.",
|
||||
"prefs.default": "기본값",
|
||||
"prefs.design": "설계 기본값",
|
||||
@@ -1548,12 +1576,16 @@
|
||||
"prefs.graphics": "그래픽",
|
||||
"prefs.graphics_note": "속도와 부드러움 중에서 선택합니다. 각 선택의 효과가 샘플에 표시됩니다.",
|
||||
"prefs.graphics_presets_note": "프리셋은 아래의 선택 항목을 한 번에 설정합니다.",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out": "축소 시 구속 조건 기호 숨기기",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out_note": "스케치를 충분히 축소하면 구속 조건 기호가 가려지지 않도록 숨깁니다. 끄기: 확대/축소와 관계없이 고정된 화면 크기를 유지합니다.",
|
||||
"prefs.history": "이력",
|
||||
"prefs.history_origin_bodies": "원점과 바디를 맨 위에 표시",
|
||||
"prefs.history_origin_bodies_note": "왼쪽 또는 브라우저 아래의 히스토리가 활성 구성 요소의 바디 폴더와 원점으로 시작하며, 브라우저처럼 표시 아이콘과 메뉴가 있습니다. 아래쪽 히스토리는 바뀌지 않습니다.",
|
||||
"prefs.history_play_button": "기록 컨트롤에 기록 재생 버튼 표시",
|
||||
"prefs.history_play_button_note": "기록 컨트롤의 한 단계 뒤로와 한 단계 앞으로 사이에 기록 재생을 추가합니다. 컨트롤을 마우스 오른쪽 버튼으로 클릭해 표시하거나 숨길 수도 있습니다.",
|
||||
"prefs.hold_stop_snapping": "누르고 있으면 스냅 중지",
|
||||
"prefs.home_fit_size": "홈·맞춤 크기",
|
||||
"prefs.home_fit_size_note": "홈, 맞춤, 연 디자인 또는 뷰 탐색기의 뷰 변경으로 모델을 화면에 맞출 때 모델이 뷰에서 차지하는 비율. 아래 설정과 관계없이 적용됩니다. 100 %: 패널, 나침반, 내비게이션 바 사이의 뷰를 가득 채웁니다.",
|
||||
"prefs.icons_only": "아이콘만",
|
||||
"prefs.imported_file": "가져온 파일",
|
||||
"prefs.input": "입력",
|
||||
@@ -1562,12 +1594,15 @@
|
||||
"prefs.interface_note": "SolidCraft의 모양과 각 부분의 위치입니다.",
|
||||
"prefs.interval_minutes": "{n}분",
|
||||
"prefs.labels": "레이블",
|
||||
"prefs.language_system": "시스템",
|
||||
"prefs.layout": "레이아웃",
|
||||
"prefs.layout_note": "컴팩트는 패널을 창 가장자리에 고정합니다. 브라우저 반투명은 플로팅에서 사용할 수 있습니다. 어시스턴트 위치는 어시스턴트 페이지에서 바꿀 수 있습니다.",
|
||||
"prefs.left": "왼쪽",
|
||||
"prefs.left_click": "왼쪽 클릭",
|
||||
"prefs.line_drag_draws_one": "누른 채 드래그하면 선 하나 그리기",
|
||||
"prefs.line_drag_draws_one_note": "선 도구에서 누르고 드래그한 뒤 놓으면 누른 곳에서 놓은 곳까지 선 하나를 그리고 거기서 끝납니다. 클릭하면 이전처럼 이어지는 선을 그립니다. 끄면: 드래그는 클릭처럼 놓은 곳에 점을 둡니다.",
|
||||
"prefs.line_hover_tangent_arc": "선의 마지막 점에 머무르면 접선 호로 전환",
|
||||
"prefs.line_hover_tangent_arc_note": "선 도구에서 선분을 그린 뒤 체인의 마지막 점에서 벗어났다가 돌아와 포인터를 그 위에 멈추면, 다음 클릭으로 접선 호의 끝점을 지정합니다. 같은 동작으로 선으로 돌아갑니다. 끔: 머물러도 아무 일도 일어나지 않습니다.",
|
||||
"prefs.live_input": "실시간 입력",
|
||||
"prefs.live_preview": "실시간 미리보기",
|
||||
"prefs.max_file_size": "열 수 있는 최대 파일 크기",
|
||||
@@ -1584,6 +1619,8 @@
|
||||
"prefs.mouse_mapping": "마우스 매핑",
|
||||
"prefs.navigation": "탐색",
|
||||
"prefs.navigation_note": "마우스, 트랙패드, 3D 마우스로 뷰를 움직이는 방식입니다.",
|
||||
"prefs.navigator_fit": "뷰 탐색기로 뷰를 바꾼 뒤 모델 맞춤",
|
||||
"prefs.navigator_fit_note": "큐브의 면, 모서리, 화살표나 기즈모의 축을 클릭하면 어느 방향에서든 전체가 들어가는 한 거리(경계 구)에서 모델의 중심을 바라봅니다. 켜져 있는 동안 홈 뷰도 같은 확대/축소와 중심을 쓰므로 그 뒤에 고른 뷰는 방향만 바뀝니다. 끄면 뷰가 제자리에서 회전하며 대상과 확대/축소를 유지합니다.",
|
||||
"prefs.not_on_gpu": "이 GPU에서는 사용할 수 없음",
|
||||
"prefs.on": "켜짐",
|
||||
"prefs.opaque": "불투명",
|
||||
@@ -1592,8 +1629,12 @@
|
||||
"prefs.origin_plane_names": "원점 평면 이름",
|
||||
"prefs.origin_plane_names_note": "브라우저, 대화 상자, 목록에 표시되는 이름입니다. {top}은 XY, {front}는 XZ, {right}는 YZ이며 Z가 위쪽입니다. 명령, 스크립트, 저장된 디자인은 XY, XZ, YZ를 유지합니다.",
|
||||
"prefs.overall_speed": "전체 속도",
|
||||
"prefs.persistent_ribbon_pressed": "활성 리본 명령 강조 표시",
|
||||
"prefs.persistent_ribbon_pressed_help": "효과가 켜져 있는 동안 리본 명령을 강조 표시합니다. 끄면 이전의 중립적인 모양과 명령 도움말을 유지합니다.",
|
||||
"prefs.perspective_fov": "시야각",
|
||||
"prefs.preview_choices": "선택 항목 미리보기",
|
||||
"prefs.print_face_highlight": "출력 바닥면 강조",
|
||||
"prefs.print_face_highlight_tip": "뷰에서 바디의 출력 바닥면을 색칠하고 윤곽을 그리는 강도입니다. 0 %이면 강조하지 않습니다.",
|
||||
"prefs.project_options_dialog": "Project 옵션 대화상자",
|
||||
"prefs.project_options_dialog_note": "켜기: 투영 전에 지오메트리 또는 바디와 투영 링크를 선택합니다. 끄기: 기존 직접 선택 작업 흐름을 유지합니다.",
|
||||
"prefs.quality_default": "기본값",
|
||||
@@ -1601,6 +1642,8 @@
|
||||
"prefs.quality_slowest": "가장 느림",
|
||||
"prefs.quality_smoother": "더 부드럽게",
|
||||
"prefs.reports_saved": "{n}개 저장됨",
|
||||
"prefs.ribbon_click_ends_tool": "실행 중인 도구의 버튼을 클릭하면 도구 종료",
|
||||
"prefs.ribbon_click_ends_tool_note": "사용 중인 스케치 도구의 강조된 리본 버튼을 클릭하면 도구가 종료되어 뷰에서 클릭하면 다시 선택됩니다. 끄기: 클릭하면 도구가 다시 시작됩니다.",
|
||||
"prefs.right_click": "오른쪽 클릭",
|
||||
"prefs.saving": "자동 저장 및 복구",
|
||||
"prefs.scale_note": "창에서 Ctrl + / Ctrl −로도 조절합니다. 버튼은 100%에서 28 px입니다.",
|
||||
@@ -1609,6 +1652,8 @@
|
||||
"prefs.search_empty": "일치하는 설정이 없습니다",
|
||||
"prefs.select": "선택",
|
||||
"prefs.select_one_item": "항목 하나 선택",
|
||||
"prefs.select_other_hidden": "다른 항목 선택으로 숨겨진 형상 선택",
|
||||
"prefs.select_other_hidden_help": "켜짐: 포인터 근처의 숨겨진 바디, 스케치 및 가려진 모서리를 포함합니다. 꺼짐: 포인터 바로 아래에 보이는 형상만 포함하는 기존 목록을 사용합니다.",
|
||||
"prefs.selecting": "선택",
|
||||
"prefs.shift": "Shift",
|
||||
"prefs.shift_add_ctrl_toggle": "Shift는 추가만, Ctrl / Cmd는 토글",
|
||||
@@ -1620,6 +1665,11 @@
|
||||
"prefs.sketch_align_points_note": "그리는 동안 점이 한 스케치 점과 수평으로, 다른 점과 수직으로 동시에 맞춰지고 점선 안내선이 표시됩니다. 클릭하면 두 정렬이 모두 유지됩니다. 끄기: 이전 점에만, 한 번에 한 축씩 맞춥니다.",
|
||||
"prefs.sketch_conflict_colour": "충돌하는 기하를 충돌 색상으로 표시",
|
||||
"prefs.sketch_conflict_colour_note": "스케치의 구속 조건이 충돌하는 동안 실패한 구속 조건의 글리프나 치수뿐 아니라 그 구속 조건이 잡고 있는 곡선과 점도 충돌 색상으로 그립니다. 끄기: 평소 색상을 유지합니다.",
|
||||
"prefs.sketch_construction_lines": "확장 보조 직선 도구",
|
||||
"prefs.sketch_open_look_at": "스케치를 열 때 정면으로 돌리기",
|
||||
"prefs.sketch_open_look_at_note": "끄기: 스케치를 만들거나 편집해도 뷰가 그대로입니다. 필요할 때 '바라보기'로 스케치를 정면으로 봅니다.",
|
||||
"prefs.sketch_recent_snap": "최근 중심과 중점에 자동 스냅",
|
||||
"prefs.sketch_recent_snap_note": "그리는 동안 최근에 사용한 두 원의 중심 또는 직선 모서리 중점의 안내선이 만나는 위치로 커서를 스냅합니다. 끄기: 안내선은 보기만 하고 커서는 움직이지 않습니다.",
|
||||
"prefs.sketch_selection": "스케치 및 선택",
|
||||
"prefs.sketch_selection_heading": "스케치 및 선택",
|
||||
"prefs.sketch_selection_note": "스케치가 스냅되는 방식과 클릭으로 선택하는 방식입니다.",
|
||||
@@ -1629,6 +1679,8 @@
|
||||
"prefs.sketch_tab_always_note": "스케치가 열려 있지 않을 때도 스케치 탭이 리본에서 모델 바로 다음에 남아 있습니다. 그 그리기 도구는 선택한 평면이나 면, 또는 다음에 고르는 평면에서 스케치를 시작하고 그 안에서 도구를 바로 쓸 수 있게 합니다.",
|
||||
"prefs.sketch_tracking_guides": "중심 및 중점 정렬 안내선",
|
||||
"prefs.sketch_tracking_guides_note": "원 중심이나 직선 모서리의 중점에 마우스를 올린 다음 수평 또는 수직으로 이동하면 임시 점선 안내선이 표시됩니다.",
|
||||
"prefs.sketch_tracking_points": "그리는 동안 끝점과 모서리에서도 정렬 안내선",
|
||||
"prefs.sketch_tracking_points_note": "그리기 도구가 점을 기다리는 동안 선이나 호의 끝점, 직사각형 모서리, 자유 점에 마우스를 올리면 중심이나 중점과 같은 임시 점선 안내선이 표시됩니다. 끄면: 중심과 중점만.",
|
||||
"prefs.sketching": "스케치",
|
||||
"prefs.snap_drawing_note": "스케치 점을 그리거나 드래그하는 동안.",
|
||||
"prefs.source": "소스",
|
||||
@@ -1640,6 +1692,24 @@
|
||||
"prefs.status_error": "오류",
|
||||
"prefs.status_selected": "선택됨",
|
||||
"prefs.status_warning": "경고",
|
||||
"prefs.structure.appearance": "모양",
|
||||
"prefs.structure.appearance_note": "색상, 텍스트 및 접근성.",
|
||||
"prefs.structure.in_profile": "프로필에 포함",
|
||||
"prefs.structure.layout": "레이아웃",
|
||||
"prefs.structure.layout_note": "창 구성 요소의 위치.",
|
||||
"prefs.structure.look": "보기",
|
||||
"prefs.structure.measure_pointer": "측정 및 포인터",
|
||||
"prefs.structure.mouse3d": "3D 마우스",
|
||||
"prefs.structure.mouse3d_note": "SpaceMouse 및 SpaceNavigator.",
|
||||
"prefs.structure.navigation_note": "마우스와 트랙패드. 3D 마우스는 별도 페이지에 있습니다.",
|
||||
"prefs.structure.profile": "프로필",
|
||||
"prefs.structure.profile_edited": "저장 후 변경됨",
|
||||
"prefs.structure.profile_hover": "설정 프로필에 저장됨",
|
||||
"prefs.structure.scale_percent": "{percent}%",
|
||||
"prefs.structure.sketch": "스케치",
|
||||
"prefs.structure.tools": "도구",
|
||||
"prefs.structure.tools_note": "모델링 도구의 동작.",
|
||||
"prefs.structure.work": "작업",
|
||||
"prefs.supersampling_brief": "뷰를 더 크게 그린 뒤 줄여서 필터링합니다. 매우 선명하지만 더 무겁습니다.",
|
||||
"prefs.tab_accent_note": "강조 색상이 활성 탭을 따라갑니다",
|
||||
"prefs.theme_file": "테마 파일",
|
||||
@@ -1649,6 +1719,16 @@
|
||||
"prefs.theme_follow_note": "다른 도구가 파일을 다시 쓸 때마다 다시 불러옵니다. 테마를 선택하면 따르기를 중지합니다.",
|
||||
"prefs.theme_follow_off": "끄기",
|
||||
"prefs.theme_follow_stop": "따르기 중지",
|
||||
"prefs.theme_option_opacity": "불투명도",
|
||||
"prefs.theme_option_opacity_help": "플로팅 패널의 불투명도를 조정합니다. 뷰포트 색상 위에서도 텍스트를 읽을 수 있도록 최솟값이 적용됩니다.",
|
||||
"prefs.theme_option_tab_colours": "탭 색상",
|
||||
"prefs.theme_option_tab_colours_help": "각 리본 탭에 이 테마의 패널 및 뷰포트 색상을 사용합니다.",
|
||||
"prefs.theme_option_tab_fade_ms": "탭 전환",
|
||||
"prefs.theme_option_tab_fade_ms_help": "탭을 전환할 때 패널 및 뷰포트 색상을 서서히 변경합니다. 0이면 즉시 전환합니다.",
|
||||
"prefs.theme_options_badge": "옵션",
|
||||
"prefs.theme_options_more": "더 보기 · {count}",
|
||||
"prefs.theme_options_reset": "초기화",
|
||||
"prefs.theme_options_unavailable": "이 기기에서는 사용할 수 없음",
|
||||
"prefs.timeline_half_hour": "−30분",
|
||||
"prefs.timeline_now": "지금",
|
||||
"prefs.timeline_quarter_hour": "−15",
|
||||
@@ -1668,10 +1748,20 @@
|
||||
"prefs.under_cursor": "커서 아래",
|
||||
"prefs.units_precision": "단위 및 정밀도",
|
||||
"prefs.updates": "업데이트",
|
||||
"prefs.value_boxes_in_view": "뷰에서 핸들 옆에 값 표시",
|
||||
"prefs.value_boxes_in_view_tip": "명령의 값(거리, 반경 등)을 모델 위 핸들 옆 상자에 표시합니다. 끄면 값은 명령 창에 입력하며, 선택 후 키보드 입력이 그 창으로 가고 모델을 가리는 것이 없습니다.",
|
||||
"prefs.view": "뷰 동작",
|
||||
"prefs.view_confirm_corner": "뷰 모서리에 확인 및 취소",
|
||||
"prefs.view_confirm_corner_note": "대화 상자나 스케치가 열려 있는 동안 뷰 오른쪽 위의 체크와 X 표시가 대화 상자의 확인과 취소와 같은 동작을 하거나 스케치를 마치고 취소합니다. 뷰 탐색기는 그 아래로 내려갑니다.",
|
||||
"prefs.viewport": "뷰포트",
|
||||
"prefs.viewport_analysis_status": "뷰포트 해석 상태 표시",
|
||||
"prefs.viewport_analysis_status_help": "활성 해석을 뷰포트 위에 표시하고 각 항목에서 범례를 엽니다. Esc로 최신 해석을 끕니다. 끄면 모서리 범례와 이전 Esc 동작으로 돌아갑니다.",
|
||||
"prefs.viewport_section_status": "뷰포트 단면 상태 표시",
|
||||
"prefs.viewport_section_status_help": "뷰포트에 단면 설정을 표시합니다. Escape 키와 활성 리본 버튼으로 단면을 끕니다. 비활성화하면 이전 단면 조작을 유지합니다.",
|
||||
"prefs.viewport_status_details": "뷰포트 실시간 상세 정보",
|
||||
"prefs.viewport_status_details_help": "표준 상세 카드에서 활성 분석 및 단면 설정을 편집합니다. 끄면 읽기 전용 분석 범례와 단면 대화상자로 돌아갑니다.",
|
||||
"prefs.viewport_status_summary": "뷰포트 상태 항목 요약",
|
||||
"prefs.viewport_status_summary_help": "상태 항목이 3개 이상이면 하나의 요약 배지로 표시합니다. 비활성화하면 모든 항목을 기존 행에 표시합니다.",
|
||||
"prefs.wheel": "휠",
|
||||
"prefs.wheel_trackpad": "휠 및 트랙패드",
|
||||
"prefs.workspace": "작업 공간",
|
||||
@@ -1681,6 +1771,10 @@
|
||||
"properties.title": "속성: {name}",
|
||||
"recovery.days_ago": "{count}일 전",
|
||||
"recovery.detail": "{file} · 피처 {features}개 · {when} 자동 저장",
|
||||
"recovery.discard_all": "모두 버리기",
|
||||
"recovery.discard_all_detail": "이 작업은 되돌릴 수 없습니다.",
|
||||
"recovery.discard_all_title": "자동 저장 {count}개를 버리시겠습니까?",
|
||||
"recovery.discard_all_title_one": "자동 저장 1개를 버리시겠습니까?",
|
||||
"recovery.hours_ago": "{count}시간 전",
|
||||
"recovery.just_now": "방금",
|
||||
"recovery.min_ago": "{count}분 전",
|
||||
@@ -2232,7 +2326,9 @@
|
||||
"render.output_ready": "렌더링 준비 완료",
|
||||
"render.output_run_check": "검사 실행",
|
||||
"render.output_size_limit": "{method}: 한 변 최대 {dimension} px, 총 {pixels} 픽셀. 가능한 최대 크기: {width} × {height}.",
|
||||
"render.output_size_method_profile": "{width} × {height}을(를) 렌더링하려면 {method}와(과) {profile} CPU 리소스 프로필을 선택하거나 더 작은 크기를 선택하세요.",
|
||||
"render.output_size_ok": "크기 정상 · {width} × {height} px",
|
||||
"render.output_size_profile": "{width} × {height}을(를) 렌더링하려면 {profile} CPU 리소스 프로필이나 더 작은 크기를 선택하세요.",
|
||||
"render.output_tools_inspector": "출력 검사기에서 크기와 형식을 편집하세요.",
|
||||
"render.output_view_image": "이미지 보기",
|
||||
"render.paint_label": "칠하기",
|
||||
@@ -2364,6 +2460,7 @@
|
||||
"render.size_custom": "사용자 지정…",
|
||||
"render.size_full_hd": "풀 HD",
|
||||
"render.size_hd": "HD",
|
||||
"render.size_needs_profile": "{size} · {profile} 필요",
|
||||
"render.size_presets": "크기 프리셋",
|
||||
"render.size_presets_pending": "출력 편집기와 함께 제공 예정",
|
||||
"render.size_preview": "미리보기",
|
||||
@@ -2585,6 +2682,24 @@
|
||||
"sheet.flange_type_base": "베이스",
|
||||
"sheet.flange_type_contour": "윤곽",
|
||||
"sheet.flange_type_edge": "모서리",
|
||||
"sheet.personal_rules.confirm_delete": "삭제 확인",
|
||||
"sheet.personal_rules.delete": "삭제",
|
||||
"sheet.personal_rules.delete_prompt": "이 개인 규칙을 삭제할까요? 설계에 이미 있는 규칙은 바뀌지 않습니다.",
|
||||
"sheet.personal_rules.full": "개인 라이브러리에 이미 규칙이 64개 있습니다.",
|
||||
"sheet.personal_rules.invalid_name": "줄 바꿈이나 제어 문자가 없는 짧은 이름을 입력하세요.",
|
||||
"sheet.personal_rules.invalid_values": "규칙 값을 모두 입력하세요. 각 값은 이 설계에서 계산할 수 있어야 하며, 두께는 양수, K 계수는 0에서 1 사이여야 합니다.",
|
||||
"sheet.personal_rules.missing": "선택한 개인 규칙을 더 이상 사용할 수 없습니다.",
|
||||
"sheet.personal_rules.name": "규칙 이름",
|
||||
"sheet.personal_rules.name_exists": "같은 이름의 개인 규칙이 이미 있습니다. 다른 이름을 사용하세요.",
|
||||
"sheet.personal_rules.name_hint": "고유한 이름",
|
||||
"sheet.personal_rules.overwrite": "선택한 개인 규칙에 변경 사항 저장",
|
||||
"sheet.personal_rules.rename": "이름 바꾸기",
|
||||
"sheet.personal_rules.rule": "개인 규칙",
|
||||
"sheet.personal_rules.save": "새로 저장",
|
||||
"sheet.personal_rules.scope": "모든 설계에서 쓸 수 있도록 프로필에 저장됩니다.",
|
||||
"sheet.personal_rules.select": "규칙 선택",
|
||||
"sheet.personal_rules.title": "개인 규칙",
|
||||
"sheet.personal_rules.unsupported": "이 규칙에는 이 버전에서 사용할 수 없는 값이 있습니다.",
|
||||
"shortcut.json_error": "매개변수는 JSON 형식이어야 합니다: {error}",
|
||||
"shortcut.no_command": "`{id}` 명령이 없습니다. JSON 앞의 텍스트는 명령 ID여야 합니다",
|
||||
"shortcut.pin": "S 상자 맨 위에 고정",
|
||||
@@ -2769,6 +2884,8 @@
|
||||
"ui.3d_mouse_step_twist_counterclockwise": "캡을 시계 반대 방향으로 돌려 유지한 다음 놓으세요.",
|
||||
"ui.3d_mouse_switch_cap": "중앙 복귀형으로 보정",
|
||||
"ui.3d_mouse_switch_trackball": "트랙볼로 보정",
|
||||
"ui.3d_mouse_use_direct": "직접 드라이버 사용",
|
||||
"ui.3d_mouse_use_direct_tip": "spacenavd를 거치지 않고 3D 마우스를 직접(hidraw) 읽습니다.",
|
||||
"ui.3d_mouse_view_axis": "뷰 축",
|
||||
"ui.3d_mouse_view_off": "끔",
|
||||
"ui.3d_mouse_view_off_tip": "3D 마우스 드라이버 프로필이 이 축을 끄므로, 이 축의 동작으로는 뷰가 움직이지 않습니다. 여기서 다른 축의 동작을 고르면 둘이 바뀌고, 그 동작은 더 이상 뷰를 움직이지 않습니다.",
|
||||
@@ -2805,6 +2922,7 @@
|
||||
"ui.agent_chat_auth_terminal": "터미널에서 이것을 실행한 뒤 다시 연결을 누르세요:",
|
||||
"ui.agent_chat_auth_title": "에이전트에 로그인",
|
||||
"ui.agent_chat_cancel": "취소",
|
||||
"ui.agent_chat_cannot_start": "설치되어 있지만 시작되지 않습니다: {error}",
|
||||
"ui.agent_chat_changes": "변경 {n}개, 실행 취소 한 번",
|
||||
"ui.agent_chat_changes_of": "변경 {n}/{limit}",
|
||||
"ui.agent_chat_close": "닫기",
|
||||
@@ -2881,9 +2999,12 @@
|
||||
"ui.agent_chat_queued_stopped": "대기 중 (중지됨, 보내지 않음)",
|
||||
"ui.agent_chat_refresh": "새로 고침",
|
||||
"ui.agent_chat_refused": "에이전트에게 허용되지 않음: {reason}",
|
||||
"ui.agent_chat_reinstall": "{agent}이(가) 설치되어 있지만({program}) SolidCraft가 확인할 때 시작되지 않았습니다: {error}\n설치가 완료되지 않았거나 다른 종류의 컴퓨터용일 수 있습니다. `{install}`(으)로 다시 설치하고, 터미널에서 버전이 출력되는지 확인한 뒤 새로 고침을 누르세요.",
|
||||
"ui.agent_chat_remove": "대기열에서 제거",
|
||||
"ui.agent_chat_remove_file": "이 메시지에서 빼기",
|
||||
"ui.agent_chat_remove_imported": "이 메시지에서 빼기. 부품은 디자인에 남습니다 (실행 취소하면 제거됨)",
|
||||
"ui.agent_chat_reply_cut_off": "응답이 끝나기 전에 길이 한도에 도달해 불완전할 수 있습니다. 에이전트에게 계속하거나 더 짧게 답하라고 요청하세요.",
|
||||
"ui.agent_chat_reply_declined": "모델이 이 메시지에 대한 답변을 거절했습니다.",
|
||||
"ui.agent_chat_right": "오른쪽",
|
||||
"ui.agent_chat_save": "저장",
|
||||
"ui.agent_chat_send": "보내기",
|
||||
@@ -2937,12 +3058,17 @@
|
||||
"ui.ai_copy_suffix": "복사본",
|
||||
"ui.ai_custom_url": "사용자 지정 URL",
|
||||
"ui.ai_default": "기본값",
|
||||
"ui.ai_edit": "편집",
|
||||
"ui.ai_edit_agent_title": "에이전트 편집",
|
||||
"ui.ai_edit_gone": "이 에이전트는 제거되었으므로 저장할 내용이 없습니다.",
|
||||
"ui.ai_edit_tip": "이 에이전트의 이름, 명령 또는 엔드포인트를 변경합니다. 저장된 키는 표시되지 않습니다.",
|
||||
"ui.ai_http_busy": "엔드포인트가 바쁘거나 한도에 도달했습니다. 나중에 다시 시도하세요",
|
||||
"ui.ai_http_key": "엔드포인트가 키를 거부했습니다. 환경 설정 > AI에서 확인하세요",
|
||||
"ui.ai_http_not_found": "엔드포인트나 모델을 찾을 수 없습니다. 기본 URL과 모델 이름을 확인하세요",
|
||||
"ui.ai_http_too_large": "대화가 이 엔드포인트에 비해 너무 큽니다. 새 채팅을 시작하세요",
|
||||
"ui.ai_key": "API 키",
|
||||
"ui.ai_key_hint": "선택 사항, 시스템 키체인에 저장",
|
||||
"ui.ai_key_keep_hint": "저장된 키를 유지하려면 비워 두세요",
|
||||
"ui.ai_key_needs_https": "키는 HTTPS를 통해서만, 또는 이 컴퓨터로만 전송됩니다.",
|
||||
"ui.ai_key_note": "SolidCraft 설정이 아닌 시스템 키체인에 저장됩니다. 로컬 서버라면 비워 두세요.",
|
||||
"ui.ai_keychain_error": "시스템 키체인이 거부했습니다: {error}",
|
||||
@@ -2969,6 +3095,7 @@
|
||||
"ui.ai_preset": "프리셋",
|
||||
"ui.ai_remove": "제거",
|
||||
"ui.ai_reset": "재설정",
|
||||
"ui.ai_save": "저장",
|
||||
"ui.ai_settings": "AI 설정…",
|
||||
"ui.ai_show_features": "AI 기능 표시",
|
||||
"ui.ai_show_features_note": "에이전트 채팅: 이미 사용 중인 코딩 에이전트나 선택한 모델 엔드포인트가 열린 디자인을 다루는 패널입니다. 끄면 AI 버튼, 단축키, 메뉴 항목, 패널이 없고 아무것도 찾거나 시작하지 않습니다.",
|
||||
@@ -3032,6 +3159,7 @@
|
||||
"ui.circle": "원",
|
||||
"ui.circular_pattern": "원형 패턴",
|
||||
"ui.clear": "지우기",
|
||||
"ui.clear_print_face": "출력 바닥면 해제",
|
||||
"ui.clear_recent": "최근 항목 지우기",
|
||||
"ui.clear_the_selection": "선택 해제",
|
||||
"ui.click_selects_whole_bodies": "클릭하면 바디 전체 선택",
|
||||
@@ -3066,6 +3194,15 @@
|
||||
"ui.constant": "상수",
|
||||
"ui.constraints_conflict": "구속 조건 충돌",
|
||||
"ui.construction": "구성선",
|
||||
"ui.construction.angle_hint": "보조 직선: 점 클릭 후 각도 입력 또는 방향 선택",
|
||||
"ui.construction.bisector_hint": "이등분선: 교차하는 두 직선 선택 후 원하는 해 선택",
|
||||
"ui.construction.common_hint": "공통 접선: 두 원/원호 선택 후 원하는 해 선택",
|
||||
"ui.construction.contact_hint": "접선: 원/원호 또는 열린 스플라인/원뿔 곡선 선택 후 접점 선택 (자유 곡선은 끝점만)",
|
||||
"ui.construction.external_hint": "접선: 원 또는 원호, 외부 점, 원하는 해를 차례로 선택",
|
||||
"ui.construction.free_hint": "보조 직선: 두 점 클릭; 마우스 오른쪽 버튼으로 다시 시작",
|
||||
"ui.construction.point_hint": "보조 직선: 통과할 점 클릭",
|
||||
"ui.construction.reference_hint": "보조 직선: 직선 선택 후 점 선택; 마우스 오른쪽 버튼으로 참조 변경",
|
||||
"ui.construction.ribbon_label": "보조선",
|
||||
"ui.context_menu": "컨텍스트 메뉴",
|
||||
"ui.continuity_g0": "G0 꺾임",
|
||||
"ui.continuity_g1": "G1 접선",
|
||||
@@ -3091,6 +3228,7 @@
|
||||
"ui.dark": "어둡게",
|
||||
"ui.default_modelling_orientation": "기본 모델링 방향",
|
||||
"ui.delete": "삭제",
|
||||
"ui.delete_select_first": "먼저 삭제할 항목을 선택하세요: 피처, 바디, 컴포넌트 또는 스케치 형상",
|
||||
"ui.depth": "깊이",
|
||||
"ui.design": "디자인",
|
||||
"ui.design_properties.author": "작성자",
|
||||
@@ -3104,6 +3242,40 @@
|
||||
"ui.design_properties.part_number": "부품 번호",
|
||||
"ui.design_properties.project": "프로젝트",
|
||||
"ui.design_properties.revision": "리비전",
|
||||
"ui.details_access_caption": "선택한 방향에서 공구가 각 면에 도달할 수 있는지 표시합니다.",
|
||||
"ui.details_angle": "각도",
|
||||
"ui.details_continuity_caption": "선택한 이음부를 편집합니다. 다른 이음부는 각자의 설정을 유지합니다.",
|
||||
"ui.details_continuity_stale": "이전 형상입니다. 이 이음부를 편집하거나 화면에 맞추려면 분석을 다시 실행하세요.",
|
||||
"ui.details_copy_list": "목록 복사",
|
||||
"ui.details_curvature": "곡률 공차",
|
||||
"ui.details_curvature_caption": "각 면의 국소 곡률 반지름에 따라 색상이 표시됩니다.",
|
||||
"ui.details_direction": "공구 방향",
|
||||
"ui.details_draft_caption": "금형 분리 방향에 대한 각 면의 각도에 따라 색상이 표시됩니다.",
|
||||
"ui.details_edit_seam": "이음부 편집",
|
||||
"ui.details_fixture": "UI 구성 요소 예시 — 샘플 데이터만 표시",
|
||||
"ui.details_fixture_caption": "설명용 값을 사용하는 UI 구성 요소 예시입니다. 모델의 분석 결과가 아닙니다.",
|
||||
"ui.details_fixture_problem": "문제가 있는 결과 예시",
|
||||
"ui.details_fixture_readout": "측정값 예시",
|
||||
"ui.details_flip": "뒤집기",
|
||||
"ui.details_gap": "간격",
|
||||
"ui.details_hatch": "절단면 해칭",
|
||||
"ui.details_jump": "곡률 불연속",
|
||||
"ui.details_key": "범례",
|
||||
"ui.details_offset": "오프셋",
|
||||
"ui.details_plane": "평면",
|
||||
"ui.details_pull": "금형 분리 방향",
|
||||
"ui.details_radius": "반지름",
|
||||
"ui.details_readout": "측정값",
|
||||
"ui.details_samples": "샘플 수",
|
||||
"ui.details_seam": "{body} · 모서리 {edge}",
|
||||
"ui.details_settings": "설정",
|
||||
"ui.details_sharp_gap": "날카로운 이음 또는 간격",
|
||||
"ui.details_show_all": "전체 {count}개 표시",
|
||||
"ui.details_smooth": "매끄러움",
|
||||
"ui.details_stripes": "줄무늬",
|
||||
"ui.details_target": "형상에 맞게 보기 조정",
|
||||
"ui.details_worst_seams": "연속성이 가장 나쁜 이음부",
|
||||
"ui.details_zebra_caption": "반사된 줄무늬는 면이 얼마나 매끄럽게 이어지는지 보여 줍니다.",
|
||||
"ui.diameter": "지름",
|
||||
"ui.dimension": "치수",
|
||||
"ui.direct_interaction": "직접 조작",
|
||||
@@ -3148,6 +3320,7 @@
|
||||
"ui.edit_in_place_saved_elsewhere": "부품이 다른 파일에 저장되었습니다. 어셈블리는 여전히 {name}에 연결되어 있습니다",
|
||||
"ui.edit_in_place_wait": "디자인에서 실행 중인 작업이 끝날 때까지 기다리세요",
|
||||
"ui.edit_section_analysis": "단면 분석 편집",
|
||||
"ui.edit_sketch_empty": "편집할 스케치가 없습니다",
|
||||
"ui.ellipse": "타원",
|
||||
"ui.emboss_wrap_note": "지원되는 원통에 접하는 직교 선 프로파일은 자동으로 감깁니다. 대상을 고르려면 벽을 선택하세요.",
|
||||
"ui.end_radius": "끝 반지름",
|
||||
@@ -3158,12 +3331,15 @@
|
||||
"ui.equation_explicit": "명시적",
|
||||
"ui.equation_form": "형식",
|
||||
"ui.equation_note": "변수는 단위가 없는 수입니다. sin(t)는 라디안으로 읽습니다. 단위가 없는 결과는 디자인 단위입니다.",
|
||||
"ui.equation_note_range": "변수는 범위와 같이 길이입니다. 길이 매개변수와 함께 쓸 수 있으며, sin()에는 길이로 나누어 넣습니다. 단위가 없는 결과는 디자인 단위로 읽습니다.",
|
||||
"ui.equation_parametric": "매개변수식",
|
||||
"ui.equation_variable_unit": "변수에 범위의 단위 사용",
|
||||
"ui.equation_x_of_t": "x(t)",
|
||||
"ui.equation_y_of_t": "y(t)",
|
||||
"ui.equation_y_of_x": "y(x)",
|
||||
"ui.equivalent_radius": "등가 반지름",
|
||||
"ui.expand": "펼치기",
|
||||
"ui.explode_needs_two_components": "분해 보기는 구성 요소를 서로 떼어 놓으므로 설계에 구성 요소가 두 개 이상 있어야 합니다(새 구성 요소, 설계 삽입 또는 바디로 구성 요소 만들기)",
|
||||
"ui.exportDxf": "DXF 내보내기…",
|
||||
"ui.export_ellipsis_keymap": "내보내기…",
|
||||
"ui.export_keymap_tip": "키, S 상자 즐겨찾기, 도구 모음을 파일로 내보내기",
|
||||
@@ -3321,12 +3497,14 @@
|
||||
"ui.joints": "조인트",
|
||||
"ui.keyboard_shortcuts": "키보드 단축키",
|
||||
"ui.language": "언어",
|
||||
"ui.lasso_select": "올가미(자유롭게 둘러 그리기: 완전히 안쪽에 있는 것을 선택)",
|
||||
"ui.layout_compact": "컴팩트",
|
||||
"ui.layout_floating": "플로팅",
|
||||
"ui.length": "길이",
|
||||
"ui.length_decimals": "길이 소수점 자릿수",
|
||||
"ui.light": "밝게",
|
||||
"ui.line": "선",
|
||||
"ui.line_arc_hint": "접선 호: 호의 끝점을 클릭합니다. 선으로 돌아가려면 마지막 점에 다시 머무르고, 끝내려면 오른쪽 클릭 또는 Esc를 누릅니다",
|
||||
"ui.lock": "잠금",
|
||||
"ui.loft": "로프트",
|
||||
"ui.look_at": "바라보기",
|
||||
@@ -3406,6 +3584,7 @@
|
||||
"ui.part_size_shared": "부품을 다시 빌드하며 추가된 피처는 모두 대체됩니다. 이 구성요소의 모든 인스턴스가 업데이트됩니다.",
|
||||
"ui.paste": "붙여넣기",
|
||||
"ui.path": "경로",
|
||||
"ui.pattern_object_type_tip": "바디: 뷰나 브라우저에서 선택하는 솔리드 형상이며, 각각 통째로 복사됩니다.\n피처: 돌출이나 구멍 같은 기록의 단계이며, 기록에서 또는 그 단계가 만든 면에서 선택합니다. 그 단계가 반복됩니다.\n스케치는 둘 다 아닙니다. 곡선은 스케치 안의 패턴이나 대칭 복사로 반복하거나, 먼저 돌출하세요.",
|
||||
"ui.pattern_on_path": "경로 패턴",
|
||||
"ui.perpendicular": "수직",
|
||||
"ui.perspective_view": "원근 투영 뷰",
|
||||
@@ -3437,6 +3616,11 @@
|
||||
"ui.polygon": "다각형",
|
||||
"ui.preferences": "환경 설정",
|
||||
"ui.press_a_key": "키를 누르세요…",
|
||||
"ui.print_face_cleared": "{body}: 출력 바닥면을 해제했습니다",
|
||||
"ui.print_face_input": "출력 바닥면",
|
||||
"ui.print_face_one_body": "출력 바닥면은 바디마다 하나입니다. 변경하려면 그 바디만 보내십시오",
|
||||
"ui.print_face_pick": "솔리드 바디의 평면 하나를 선택하면 출력 바닥면이 됩니다",
|
||||
"ui.print_face_set": "{body}: 출력 바닥면을 설정했습니다. 슬라이서로 보내면 이 면이 아래로 놓입니다",
|
||||
"ui.profile": "프로파일",
|
||||
"ui.profile_plane": "프로파일 평면",
|
||||
"ui.profiles": "프로파일",
|
||||
@@ -3452,6 +3636,7 @@
|
||||
"ui.properties.inertia_y": "Iyx, Iyy, Iyz",
|
||||
"ui.properties.inertia_z": "Izx, Izy, Izz",
|
||||
"ui.properties.measuring": "측정 중…",
|
||||
"ui.properties.measuring_bodies": "측정 중… 바디 {total}개 중 {done}개",
|
||||
"ui.properties.measuring_failed": "측정이 끝나기 전에 중단되었습니다.",
|
||||
"ui.properties.principal_axis": "주축 {number}",
|
||||
"ui.properties.principal_moments": "주관성 모멘트",
|
||||
@@ -3513,6 +3698,7 @@
|
||||
"ui.selectOther": "기타 선택…",
|
||||
"ui.selectTangentChain": "접선 체인 선택",
|
||||
"ui.select_all": "모두 선택",
|
||||
"ui.select_components_by_face": "구성요소 선택(면을 클릭하면 해당 구성요소 선택)",
|
||||
"ui.selection": "선택",
|
||||
"ui.selection_modifiers": "선택 보조 키",
|
||||
"ui.selection_shift_add_only": "Shift+클릭은 추가만 함",
|
||||
@@ -3641,10 +3827,19 @@
|
||||
"ui.view_centre": "뷰 중심",
|
||||
"ui.viewport_status_clear": "{name} 끄기",
|
||||
"ui.viewport_status_clear_hint": "{name} 끄기 · Esc",
|
||||
"ui.viewport_status_edges": "모서리 {count}개",
|
||||
"ui.viewport_status_from": "{direction} 방향에서",
|
||||
"ui.viewport_status_key": "{name} 범례 표시",
|
||||
"ui.viewport_status_minimum_radius": "최소 반지름",
|
||||
"ui.viewport_status_pairs": "{count}쌍",
|
||||
"ui.viewport_status_section_hatch": "{setting} · 해칭",
|
||||
"ui.viewport_status_section_plane": "현재 평면",
|
||||
"ui.viewport_status_section_tilted": "기울어짐 · {offset}",
|
||||
"ui.viewport_status_stripes": "줄무늬 {count}개",
|
||||
"ui.viewport_status_summary_clear": "모두 끄기",
|
||||
"ui.viewport_status_summary_heading": "이 뷰에서",
|
||||
"ui.viewport_status_summary_label": "{name} 외 {count}개 항목",
|
||||
"ui.viewport_status_summary_more": "+{count}",
|
||||
"ui.viewport_theme_follow": "테마 따르기",
|
||||
"ui.visual_shaded_hidden_edges": "음영 처리 및 숨겨진 모서리",
|
||||
"ui.visual_shaded_with_edges": "음영 처리 및 모서리",
|
||||
@@ -3676,7 +3871,9 @@
|
||||
"update.button": "업데이트",
|
||||
"update.button_version": "{version}(으)로 업데이트",
|
||||
"update.check_automatically": "업데이트 자동 확인",
|
||||
"update.check_for_updates": "업데이트 확인",
|
||||
"update.check_now": "지금 확인",
|
||||
"update.check_unavailable": "이 설치에서는 업데이트를 확인할 수 없습니다.",
|
||||
"update.checking": "확인 중…",
|
||||
"update.copy": "복사",
|
||||
"update.dmg_opened": "디스크 이미지를 확인하고 열었습니다: SolidCraft를 응용 프로그램 폴더로 끌어 기존 버전을 바꾼 뒤 SolidCraft를 다시 시작하세요.",
|
||||
|
||||
@@ -606,6 +606,8 @@
|
||||
"cmd.appearance_library": "Biblioteca de aparências",
|
||||
"cmd.appearance_list": "Listar aparências",
|
||||
"cmd.assembly_bom": "Lista de materiais",
|
||||
"cmd.assembly_mass_properties": "Propriedades de massa",
|
||||
"cmd.body.print_face": "Face de impressão",
|
||||
"cmd.body_rename": "Renomear corpo",
|
||||
"cmd.browser_group": "Novo grupo",
|
||||
"cmd.browser_move": "Mover itens do navegador",
|
||||
@@ -815,6 +817,16 @@
|
||||
"cmd.sheet_refold": "Redobrar",
|
||||
"cmd.sheet_rules": "Listar regras de chapa metálica",
|
||||
"cmd.sheet_unfold": "Desdobrar",
|
||||
"cmd.sketch.construction_line": "Reta de construção",
|
||||
"cmd.sketch.construction_line.angle": "Reta de construção em ângulo",
|
||||
"cmd.sketch.construction_line.bisector": "Bissetriz",
|
||||
"cmd.sketch.construction_line.horizontal": "Reta de construção horizontal",
|
||||
"cmd.sketch.construction_line.parallel": "Reta de construção paralela",
|
||||
"cmd.sketch.construction_line.perpendicular": "Reta de construção perpendicular",
|
||||
"cmd.sketch.construction_line.tangent_at": "Tangente em um ponto da curva",
|
||||
"cmd.sketch.construction_line.tangent_external": "Tangente por um ponto externo",
|
||||
"cmd.sketch.construction_line.tangent_two": "Tangente comum",
|
||||
"cmd.sketch.construction_line.vertical": "Reta de construção vertical",
|
||||
"cmd.sketch_arc_center_point": "Arco por ponto central",
|
||||
"cmd.sketch_arc_tangent": "Arco tangente",
|
||||
"cmd.sketch_arc_three_point": "Arco por 3 pontos",
|
||||
@@ -1282,6 +1294,8 @@
|
||||
"prefs.orientation": "Orientação",
|
||||
"prefs.overall_speed": "Velocidade geral",
|
||||
"prefs.preview_choices": "Prévia das suas escolhas",
|
||||
"prefs.print_face_highlight": "Destaque da face de impressão",
|
||||
"prefs.print_face_highlight_tip": "Intensidade da cor e do contorno da face de impressão de um corpo na vista. 0 % não mostra destaque.",
|
||||
"prefs.quality_default": "padrão",
|
||||
"prefs.quality_fastest": "mais rápido",
|
||||
"prefs.quality_slowest": "mais lento",
|
||||
@@ -1561,6 +1575,8 @@
|
||||
"ui.3d_mouse_step_twist_counterclockwise": "Gire a tampa no sentido anti-horário, segure e solte.",
|
||||
"ui.3d_mouse_switch_cap": "Calibrar como retorno ao centro",
|
||||
"ui.3d_mouse_switch_trackball": "Calibrar como trackball",
|
||||
"ui.3d_mouse_use_direct": "Usar driver direto",
|
||||
"ui.3d_mouse_use_direct_tip": "Ler o mouse 3D diretamente (hidraw) em vez de pelo spacenavd.",
|
||||
"ui.3d_mouse_view_axis": "Eixo da vista",
|
||||
"ui.3d_mouse_view_off": "Desligado",
|
||||
"ui.3d_mouse_view_off_tip": "O perfil do driver do mouse 3D desliga este eixo, então o movimento dele não move a vista. Escolher aqui o movimento de outro eixo troca os dois, e esse movimento deixa de mover a vista.",
|
||||
@@ -1830,6 +1846,7 @@
|
||||
"ui.circle": "Círculo",
|
||||
"ui.circular_pattern": "Padrão circular",
|
||||
"ui.clear": "Limpar",
|
||||
"ui.clear_print_face": "Limpar face de impressão",
|
||||
"ui.clear_recent": "Limpar recentes",
|
||||
"ui.clear_the_selection": "Limpar a seleção",
|
||||
"ui.click_selects_whole_bodies": "O clique seleciona corpos inteiros",
|
||||
@@ -1864,6 +1881,7 @@
|
||||
"ui.constant": "Constante",
|
||||
"ui.constraints_conflict": "Restrições em conflito",
|
||||
"ui.construction": "Construção",
|
||||
"ui.construction.ribbon_label": "Linhas aux.",
|
||||
"ui.context_menu": "Menu de contexto",
|
||||
"ui.continuity_g0": "G0 vinco",
|
||||
"ui.continuity_g1": "G1 tangente",
|
||||
@@ -2187,6 +2205,11 @@
|
||||
"ui.polygon": "Polígono",
|
||||
"ui.preferences": "Preferências",
|
||||
"ui.press_a_key": "pressione uma tecla…",
|
||||
"ui.print_face_cleared": "{body}: face de impressão removida",
|
||||
"ui.print_face_input": "Face de impressão",
|
||||
"ui.print_face_one_body": "Uma face de impressão pertence a um único corpo: envie esse corpo sozinho para alterá-la",
|
||||
"ui.print_face_pick": "Selecione uma face plana de um corpo sólido para torná-la a face de impressão",
|
||||
"ui.print_face_set": "{body}: face de impressão definida; Enviar ao fatiador apoia o corpo sobre ela",
|
||||
"ui.profile": "Perfil",
|
||||
"ui.profile_plane": "Plano do perfil",
|
||||
"ui.profiles": "Perfis",
|
||||
@@ -2377,7 +2400,9 @@
|
||||
"update.button": "Atualizar",
|
||||
"update.button_version": "Atualizar para {version}",
|
||||
"update.check_automatically": "Verificar atualizações automaticamente",
|
||||
"update.check_for_updates": "Verificar atualizações",
|
||||
"update.check_now": "Verificar agora",
|
||||
"update.check_unavailable": "A verificação de atualizações não está disponível para esta instalação.",
|
||||
"update.checking": "Verificando…",
|
||||
"update.copy": "Copiar",
|
||||
"update.dmg_opened": "A imagem de disco está aberta e verificada: arraste o SolidCraft para Aplicativos, substituindo a cópia antiga, e reinicie o SolidCraft.",
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
"BLEND SURFACE": "MẶT NỐI MƯỢT",
|
||||
"BOUNDARY SURFACE": "BỀ MẶT BIÊN DẠNG",
|
||||
"BROWSER": "CÂY ĐỐI TƯỢNG",
|
||||
"Back to the original order": "Trở về thứ tự ban đầu",
|
||||
"Ball": "Cầu",
|
||||
"Bar": "Thép thanh",
|
||||
"Base Center": "Tâm đáy",
|
||||
@@ -595,6 +596,8 @@
|
||||
"Snap to face and edge centres": "Bắt vào tâm mặt và tâm cạnh",
|
||||
"SolidCraft cannot submit reports directly. Submit on GitHub; no token is needed in the app.": "SolidCraft không thể gửi báo cáo trực tiếp. Hãy gửi trên GitHub; ứng dụng không cần mã truy cập.",
|
||||
"SolidCraft closed before these designs were saved. Their last autosave can be opened.": "SolidCraft đã đóng trước khi các thiết kế này được lưu. Bạn có thể mở bản tự động lưu gần nhất của chúng.",
|
||||
"Sort A to Z": "Sắp xếp từ A đến Z",
|
||||
"Sort Z to A": "Sắp xếp từ Z đến A",
|
||||
"Spacing 2 must be a non-zero number": "Khoảng cách 2 phải là một số khác 0",
|
||||
"Spacing must be a non-zero number": "Khoảng cách phải là một số khác 0",
|
||||
"Specialise": "Chuyên biệt hóa",
|
||||
@@ -775,6 +778,8 @@
|
||||
"at the face": "tại bề mặt",
|
||||
"bom.group_children": "Chi tiết con trong hàng của chi tiết cha",
|
||||
"browser.body_name": "Thân khối{number}",
|
||||
"browser.calibrate_click_a": "Nhấp vào ảnh để chọn điểm A, hoặc nhập tọa độ của điểm đó.",
|
||||
"browser.calibrate_click_b": "Nhấp vào ảnh để chọn điểm B, hoặc nhập tọa độ của điểm đó.",
|
||||
"browser.calibrate_title": "Hiệu chuẩn: {name}",
|
||||
"browser.capture_many": "{count} chi tiết đã được di chuyển nhưng vị trí chưa được ghi lại.",
|
||||
"browser.capture_note": "Ghi vị trí sẽ giữ vị trí mới; Hoàn nguyên sẽ đặt lại như cũ.",
|
||||
@@ -817,6 +822,8 @@
|
||||
"cmd.appearance_pick_up": "Lấy diện mạo",
|
||||
"cmd.appearance_replace": "Thay diện mạo",
|
||||
"cmd.assembly_bom": "Bảng kê vật tư (BOM)",
|
||||
"cmd.assembly_mass_properties": "Thuộc tính khối lượng",
|
||||
"cmd.body.print_face": "Mặt in",
|
||||
"cmd.body_rename": "Đổi tên thân khối",
|
||||
"cmd.browser_collapse_all": "Thu gọn tất cả",
|
||||
"cmd.browser_expand_all": "Mở rộng tất cả",
|
||||
@@ -1101,6 +1108,16 @@
|
||||
"cmd.sheet_refold": "Gập lại tấm kim loại",
|
||||
"cmd.sheet_rules": "Danh sách quy tắc kim loại tấm",
|
||||
"cmd.sheet_unfold": "Trải phẳng tạm thời",
|
||||
"cmd.sketch.construction_line": "Đường thẳng dựng hình",
|
||||
"cmd.sketch.construction_line.angle": "Đường dựng hình theo góc",
|
||||
"cmd.sketch.construction_line.bisector": "Đường phân giác",
|
||||
"cmd.sketch.construction_line.horizontal": "Đường dựng hình nằm ngang",
|
||||
"cmd.sketch.construction_line.parallel": "Đường dựng hình song song",
|
||||
"cmd.sketch.construction_line.perpendicular": "Đường dựng hình vuông góc",
|
||||
"cmd.sketch.construction_line.tangent_at": "Tiếp tuyến tại điểm trên đường cong",
|
||||
"cmd.sketch.construction_line.tangent_external": "Tiếp tuyến qua điểm ngoài",
|
||||
"cmd.sketch.construction_line.tangent_two": "Tiếp tuyến chung",
|
||||
"cmd.sketch.construction_line.vertical": "Đường dựng hình thẳng đứng",
|
||||
"cmd.sketch_arc3d": "Cung tròn 3D",
|
||||
"cmd.sketch_arc_center_point": "Cung tròn xác định bởi tâm và điểm",
|
||||
"cmd.sketch_arc_tangent": "Cung tròn tiếp tuyến",
|
||||
@@ -1231,6 +1248,7 @@
|
||||
"cmd.view.render_browser": "Trình duyệt kết xuất",
|
||||
"cmd.view.render_dock": "Di chuyển neo kết xuất",
|
||||
"cmd.view.render_focus": "Chế độ xem tập trung kết xuất",
|
||||
"cmd.view.status_details": "Chi tiết trạng thái khung nhìn",
|
||||
"cmd.view.status_items": "Các mục trạng thái khung nhìn",
|
||||
"cmd.view_ambient_occlusion": "Đổ bóng che khuất môi trường (AO)",
|
||||
"cmd.view_angle_readout": "Góc hướng nhìn",
|
||||
@@ -1269,8 +1287,14 @@
|
||||
"color.hex_hint": "#rrggbb",
|
||||
"color.hue": "Sắc độ",
|
||||
"color.linear": "Đang hiển thị giá trị màu trong không gian tuyến tính 0-1",
|
||||
"color.recent": "Màu gần đây",
|
||||
"color.recent_help": "Các màu bạn chọn ở bất kỳ ô màu nào sẽ hiện ở đây",
|
||||
"color.saturation": "Độ bão hòa (phần trăm)",
|
||||
"color.saturation_value": "Độ bão hòa và giá trị",
|
||||
"color.selected": "Màu đã chọn",
|
||||
"color.step_down": "Giảm một bước",
|
||||
"color.step_up": "Tăng một bước",
|
||||
"color.value": "Giá trị, độ sáng (phần trăm)",
|
||||
"config.column_filter_empty": "Không có cột phù hợp",
|
||||
"contact.components_count": "{count} chi tiết",
|
||||
"contact.enabled_label": "đã bật",
|
||||
@@ -1317,6 +1341,7 @@
|
||||
"dialog.dimension_name": "Kích thước: {name}",
|
||||
"dialog.edit_title": "CHỈNH SỬA {title}",
|
||||
"dialog.no_shown_body": "Không có thân khối đang hiển thị để thay đổi: hãy hiển thị một thân khối, hoặc chọn “Tạo mới Thân khối”",
|
||||
"dialog.pattern_sketch_not_object": "Hãy chọn thân khối hoặc tính năng: bản phác thảo không phải là cả hai. Lặp lại các đường cong của nó bằng Mảng hoặc Lấy đối xứng trong chính bản phác thảo, hoặc đùn khối nó trước.",
|
||||
"dialog.select": "↖ Chọn",
|
||||
"dialog.selected_count": "↖ {count} đã chọn",
|
||||
"dialog.selection_guidance": "Chọn một mục đầu vào để thay đổi. Nhấp vào đối tượng đã chọn để bỏ chọn; Ctrl/Cmd-nhấp để bật/tắt chọn. Xem trước kết quả, sau đó nhấn OK.",
|
||||
@@ -1374,26 +1399,243 @@
|
||||
"from the rule": "từ quy tắc",
|
||||
"help.apache": "Giấy phép Apache 2.0",
|
||||
"help.appearance.assign": "Gán màu hoặc vẻ ngoài vật liệu cho các khối, mặt hoặc thành phần đã chọn mà không thay đổi khối lượng. Dùng để phân biệt các chi tiết hoặc xem trước lớp hoàn thiện.",
|
||||
"help.assembly.bom": "Liệt kê các chi tiết của thiết kế hoặc cụm chi tiết kèm số lượng theo mã chi tiết, và có thể lưu danh sách dạng CSV hoặc JSON. Dùng làm bảng kê vật tư để đặt hàng và lắp ráp.",
|
||||
"help.attributions": "Ghi công (ATTRIBUTION.md)",
|
||||
"help.build": "Phiên bản {version} · commit {commit} · dựng ngày {date}",
|
||||
"help.canvas.decal": "Đặt hình ảnh lên một mặt phẳng của mô hình như một đề can. Dùng để thể hiện nhãn, logo hoặc hoa văn in trên chi tiết.",
|
||||
"help.canvas.edit": "Thay đổi hình ảnh Canvas: vị trí, kích thước, góc, độ mờ đục, phản chiếu, hiển thị hoặc tên. Dùng để căn hình ảnh tham chiếu với bản phác thảo mà bạn vẽ đè lên ảnh.",
|
||||
"help.canvas.insert": "Đặt hình ảnh PNG hoặc JPEG lên mặt phẳng hoặc bề mặt làm tham chiếu bán trong suốt. Dùng để đồ lại ảnh chụp hoặc bản vẽ trong phác thảo, với ảnh được chỉnh về kích thước đã biết.",
|
||||
"help.component.break_link": "Ngắt liên kết cụm chi tiết với tệp thiết kế của nó, giữ nguyên các thân khối. Dùng khi chi tiết không còn cần cập nhật theo thay đổi trong tệp gốc.",
|
||||
"help.component.capture_position": "Lưu vị trí các chi tiết đã di chuyển bằng tay làm vị trí chính thức của chúng. Dùng sau khi kéo các chi tiết vào vị trí mà không có khớp nối nào giữ chúng.",
|
||||
"help.component.create": "Thêm một cụm chi tiết mới, rỗng vào thiết kế, bên trong cụm đang hoạt động trừ khi bạn chọn cụm cha khác. Dùng để dành không gian riêng cho các thân khối và phác thảo của một chi tiết mới trong cụm lắp ráp.",
|
||||
"help.component.finish_edit": "Lưu chi tiết đang được chỉnh sửa tại chỗ, quay lại cụm lắp ráp của nó và cập nhật cụm lắp ráp từ chi tiết đó. Dùng khi bạn đã hoàn tất các thay đổi cho chi tiết liên kết.",
|
||||
"help.component.from_bodies": "Biến mỗi thân khối được chọn thành một cụm chi tiết riêng, lấy tên theo thân khối. Dùng khi cần chuyển thiết kế gồm các thân khối rời thành cụm lắp ráp có các chi tiết nối và di chuyển được.",
|
||||
"help.component.insert_design": "Chèn một thiết kế đã lưu khác thành cụm chi tiết liên kết với tệp của nó, giữ vị trí các thân khối đặc như trong tệp đó. Dùng để tái sử dụng chi tiết trong cụm lắp ráp và nhận các thay đổi sau này bằng Cập nhật liên kết.",
|
||||
"help.component.properties": "Hiển thị thể tích, khối lượng, trọng tâm và mô men quán tính của một cụm chi tiết, dựa trên vật liệu của các thân khối trong đó. Dùng để kiểm tra khối lượng và độ cân bằng của cụm lắp ráp.",
|
||||
"help.component.revert_position": "Đưa các chi tiết đã di chuyển bằng tay về vị trí cũ, bỏ những lần di chuyển chưa lưu vị trí. Dùng để hoàn tác các lần di chuyển thử trong cụm lắp ráp.",
|
||||
"help.component.update_links": "Đọc lại các tệp thiết kế được liên kết và thay thế những thân khối đã thay đổi. Dùng sau khi chỉnh sửa một chi tiết mà cụm lắp ráp này sử dụng.",
|
||||
"help.config.configure": "Thêm tham số, tính năng, vật liệu hoặc ngoại quan làm cột của bảng cấu hình. Dùng để tạo các biến thể của một thiết kế, chẳng hạn các kích cỡ của một chi tiết.",
|
||||
"help.config.preview": "Kiểm tra xem một hàng của bảng cấu hình có dựng lại được không, mà không thay đổi thiết kế hay lịch sử của nó. Dùng trước khi chuyển sang một biến thể bạn chưa chắc chắn.",
|
||||
"help.config.rules": "Hiển thị các quy tắc của bảng cấu hình, các hàng và hàng đang kích hoạt. Dùng để xem các biến thể của thiết kế được thiết lập thế nào.",
|
||||
"help.config.table": "Hiển thị bảng cấu hình: mỗi biến thể một hàng, mỗi tham số hoặc tính năng một cột, và cho biết thiết kế còn khớp với hàng đang kích hoạt hay không. Dùng để rà soát các biến thể của thiết kế.",
|
||||
"help.connect_note": "Khởi động lại từng trợ lý ảo để nạp SolidCraft server. Mỗi tập tin cấu hình đều đã được sao lưu thành .bak trước khi thay đổi.",
|
||||
"help.connect_title": "Kết nối trợ lý ảo AI",
|
||||
"help.construct.axis.edge": "Tạo trục dựng hình dọc theo một cạnh thẳng hoặc đường phác thảo. Dùng làm trục cho Xoay tròn tạo khối, mảng tròn hoặc khớp nối.",
|
||||
"help.construct.axis.normal_to_face": "Tạo trục dựng hình đi qua một điểm và vuông góc với một mặt. Dùng làm trục nhô thẳng ra khỏi bề mặt.",
|
||||
"help.construct.axis.through_cylinder": "Tạo trục dựng hình đi qua tâm của mặt hình trụ, nón hoặc xuyến, hoặc của một cạnh tròn. Dùng để xoay hoặc tạo mảng các tính năng quanh một chi tiết tròn.",
|
||||
"help.construct.axis.two_planes": "Tạo trục dựng hình tại nơi hai mặt phẳng giao nhau. Dùng khi trục cần có chính là đường giao giữa hai mặt.",
|
||||
"help.construct.axis.two_points": "Tạo trục dựng hình đi qua hai điểm, đỉnh hoặc điểm phác thảo. Dùng cho trục chạy giữa hai vị trí đã biết.",
|
||||
"help.construct.plane.along_path": "Tạo mặt phẳng dựng hình vuông góc với một cạnh hoặc đường cong, tại một vị trí dọc theo nó. Dùng để phác thảo biên dạng cho Quét theo đường dẫn hoặc mặt cắt của đường dẫn.",
|
||||
"help.construct.plane.at_angle": "Tạo mặt phẳng dựng hình xoay một góc so với mặt phẳng hoặc mặt, quanh một trục hoặc cạnh. Dùng cho phác thảo nghiêng, chẳng hạn giá đỡ vát góc.",
|
||||
"help.construct.plane.midplane": "Tạo mặt phẳng dựng hình nằm giữa hai mặt phẳng, hoặc phân giác của chúng nơi chúng giao nhau theo một góc. Dùng làm mặt phẳng đối xứng khi Lấy đối xứng.",
|
||||
"help.construct.plane.offset": "Tạo mặt phẳng dựng hình song song với một mặt phẳng, cách một khoảng hoặc đi qua một điểm. Dùng để phác thảo ở độ cao xác định phía trên một mặt.",
|
||||
"help.construct.plane.perpendicular": "Tạo mặt phẳng dựng hình chứa một đường hoặc cạnh và vuông góc với một mặt phẳng hoặc mặt. Dùng để phác thảo thẳng đứng trên mô hình dọc theo một cạnh.",
|
||||
"help.construct.plane.tangent": "Tạo mặt phẳng dựng hình tiếp xúc với hình trụ, nón, cầu hoặc xuyến tại một điểm. Dùng để phác thảo trên mặt bên của một chi tiết tròn.",
|
||||
"help.construct.plane.three_points": "Tạo mặt phẳng dựng hình đi qua ba điểm. Dùng cho mặt phẳng xác định bởi các vị trí trên mô hình, chẳng hạn ba góc.",
|
||||
"help.construct.plane.two_edges": "Tạo mặt phẳng dựng hình đi qua hai cạnh thẳng hoặc hai đường nằm trong cùng một mặt phẳng. Dùng cho mặt phẳng cắt ngang chi tiết, chẳng hạn qua hai cạnh đối diện.",
|
||||
"help.construct.point.along_path": "Tạo điểm dựng hình tại một vị trí dọc theo cạnh hoặc đường cong. Dùng làm điểm tham chiếu ở giữa đường dẫn.",
|
||||
"help.construct.point.center": "Tạo điểm dựng hình tại tâm của cạnh tròn, đường tròn hoặc cung phác thảo, hình cầu hoặc hình xuyến. Dùng làm điểm tham chiếu cho lỗ, trục và khớp nối.",
|
||||
"help.construct.point.edge_plane": "Tạo điểm dựng hình tại nơi một cạnh hoặc đường xuyên qua một mặt phẳng. Dùng để đánh dấu chỗ đường dẫn cắt qua mặt phẳng.",
|
||||
"help.construct.point.three_planes": "Tạo điểm dựng hình tại nơi ba mặt phẳng giao nhau. Dùng làm điểm tham chiếu cho góc, kể cả khi mô hình không có đỉnh ở đó.",
|
||||
"help.construct.point.two_edges": "Tạo điểm dựng hình tại nơi hai cạnh hoặc hai đường gặp nhau, hoặc gần nhau nhất. Dùng làm điểm tham chiếu tại một góc ảo.",
|
||||
"help.construct.point.vertex": "Tạo điểm dựng hình trên một đỉnh hoặc điểm phác thảo. Dùng làm điểm tham chiếu vẫn còn khi phác thảo hay thân khối xung quanh bị ẩn.",
|
||||
"help.contact.check": "Liệt kê các cặp chi tiết trong tập hợp tiếp xúc đang xuyên qua nhau ở vị trí hiện tại. Dùng để tìm va chạm trước khi dẫn động khớp nối hoặc chạy nghiên cứu chuyển động.",
|
||||
"help.contact.create": "Gom hai hay nhiều chi tiết thành tập hợp tiếp xúc, ngăn các thân khối xuyên qua nhau khi khớp nối chuyển động. Dùng cho các chi tiết cần dừng khi chạm nhau, như đòn bẩy chạm cữ chặn.",
|
||||
"help.contact.disable_all": "Tắt tiếp xúc để khớp nối được dẫn động và nghiên cứu chuyển động không còn dừng khi các chi tiết chạm nhau. Dùng để di chuyển chi tiết tự do trở lại hoặc giữ cho cụm lắp ráp lớn phản hồi nhanh.",
|
||||
"help.contact.edit": "Thay đổi tập hợp tiếp xúc: các chi tiết, tên hoặc trạng thái tạm nén, đồng thời có thể xóa tập hợp. Dùng để điều chỉnh những chi tiết không được xuyên qua nhau.",
|
||||
"help.contact.enable_all": "Đưa mọi chi tiết của cụm lắp ráp vào một tập hợp tiếp xúc để không có hai chi tiết nào xuyên qua nhau khi khớp nối chuyển động. Dùng để kiểm tra nhanh toàn bộ cơ cấu.",
|
||||
"help.contact.enable_sets": "Bật tiếp xúc cho các tập hợp tiếp xúc đã định nghĩa để khớp nối được dẫn động và nghiên cứu chuyển động dừng tại nơi các chi tiết sắp xuyên qua nhau. Dùng để bật lại các tập hợp sau khi tắt tiếp xúc.",
|
||||
"help.contact.list": "Liệt kê các tập hợp tiếp xúc của thiết kế, các chi tiết trong mỗi tập hợp và trạng thái bật tiếp xúc. Dùng để kiểm tra thiết lập tiếp xúc trước khi dẫn động cụm lắp ráp.",
|
||||
"help.document.inspect": "Hiển thị tổng quan về thiết kế: các cụm chi tiết, thân khối, phác thảo, tính năng và tham số. Dùng để nắm nhanh một thiết kế do người khác tạo.",
|
||||
"help.document.units": "Thay đổi đơn vị hiển thị chiều dài của thiết kế, chẳng hạn mm hoặc inch. Hình học giữ nguyên kích thước; chỉ phần hiển thị và các số thuần túy thay đổi theo.",
|
||||
"help.edit.checkpoint": "Ghi nhớ thiết kế, phác thảo đang hoạt động và lịch sử hoàn tác ở trạng thái hiện tại. Dùng trước khi thử điều gì rủi ro mà bạn có thể muốn quay lại.",
|
||||
"help.edit.restore_checkpoint": "Quay về một điểm kiểm tra, kể cả lịch sử hoàn tác. Dùng để bỏ mọi thao tác đã làm kể từ điểm kiểm tra chỉ trong một bước.",
|
||||
"help.explode.create": "Tạo chế độ xem phân rã, đẩy các chi tiết ra xa tâm cụm lắp ráp hoặc theo các dịch chuyển bạn thiết lập. Dùng để thể hiện cách lắp các chi tiết trong hướng dẫn hoặc bài trình bày.",
|
||||
"help.face.delete": "Xóa các mặt đã chọn và để các mặt lân cận khép kín chỗ trống, hoặc giữ lỗ hở dưới dạng bề mặt. Dùng để bỏ một cạnh bo tròn, một lỗ hoặc một phần lồi đang vướng.",
|
||||
"help.file.insert_mesh": "Thêm tệp 3MF, STL, OBJ, PLY hoặc glTF vào thiết kế dưới dạng các thân khối lưới trong cụm chi tiết mới. Dùng để đặt mô hình tải về hoặc quét bên cạnh thiết kế làm tham chiếu.",
|
||||
"help.file.insert_step": "Thêm tệp STEP, IGES, FreeCAD hoặc Rhino vào thiết kế dưới dạng các thân khối đặc trong cụm chi tiết mới; các chi tiết của cụm lắp ráp trở thành cụm chi tiết lồng nhau. Dùng để nhập mô hình từ nhà cung cấp hoặc chương trình CAD khác.",
|
||||
"help.file.save_mesh": "Lưu các thân khối thành lưới đa giác STL, 3MF hoặc OBJ, với độ mịn của các mặt cong do bạn chọn. Dùng để chuẩn bị chi tiết cho in 3D hoặc cho các chương trình đọc lưới đa giác.",
|
||||
"help.file.send_to_slicer": "Lưu các thân khối đã chọn thành tệp 3MF và mở trong phần mềm cắt lớp bạn chọn. Dùng để chuyển từ mô hình sang in chỉ trong một bước.",
|
||||
"help.font_details": "Giao diện sử dụng các phông chữ tích hợp của egui (Ubuntu Light và Hack, theo Ubuntu Font Licence và giấy phép MIT/Bitstream Vera; Noto Emoji và phông biểu tượng emoji, theo OFL và MIT). Văn bản phác thảo dùng Liberation Sans (SIL OFL 1.1). Gói phông chữ tùy chọn của Crafting Apps, craft-fonts (BIZ UDPGothic, Shippori Mincho, BIZ UDMincho, Noto Sans CJK SC, Noto Sans Arabic; SIL OFL 1.1), không được đóng gói kèm trong các bản dựng SolidCraft.",
|
||||
"help.fonts": "Phông chữ",
|
||||
"help.frame.member": "Đặt một biên dạng, chẳng hạn ống hoặc nhôm định hình, dọc theo các đường của phác thảo khung, mỗi đường một phần tử. Dùng để dựng khung, giá đỡ và kết cấu hàn.",
|
||||
"help.inspect.accessibility": "Tô màu các mặt mà dụng cụ có thể tiếp cận từ một hướng và các mặt không tiếp cận được. Dùng để kiểm tra chi tiết có gia công hoặc ép khuôn được từ phía đó không.",
|
||||
"help.inspect.center_of_mass": "Hiển thị trọng tâm của các thân khối, từng thân riêng và tất cả cùng nhau, với giả định mật độ đồng đều. Dùng để kiểm tra cân bằng và chỗ chi tiết sẽ bị lật.",
|
||||
"help.inspect.colored_components": "Gán cho mỗi cụm chi tiết một màu tạm thời riêng, không thay đổi ngoại quan. Dùng để phân biệt các chi tiết của cụm lắp ráp chỉ trong một cái nhìn.",
|
||||
"help.inspect.compare": "So sánh hai thân khối và chỉ ra chỗ nào một thân có vật liệu mà thân kia không có, kèm thể tích và độ lệch. Dùng để đối chiếu chi tiết đã chỉnh sửa hoặc nhập vào với bản gốc.",
|
||||
"help.inspect.continuity": "Kiểm tra các mặt gặp nhau mượt đến đâu dọc theo cạnh: khe hở, gãy góc hoặc nhảy độ cong, và tô bóng các đường nối. Dùng để tìm chỗ các bề mặt nối chưa sạch.",
|
||||
"help.inspect.curvature_comb": "Vẽ các lược dọc theo đường cong, cạnh hoặc mặt, với răng lược cho thấy mức độ uốn cong. Dùng để phát hiện chỗ phẳng, chỗ gãy và độ cong không đều.",
|
||||
"help.inspect.curvature_map": "Tô màu các mặt theo độ cong, màu đỏ ở nơi bán kính nhỏ. Dùng để tìm chỗ gấp gắt và đánh giá độ mượt của bề mặt.",
|
||||
"help.inspect.draft": "Tô màu các mặt theo góc thoát khuôn so với hướng tháo khuôn, đánh dấu những mặt có góc quá nhỏ. Dùng để kiểm tra chi tiết trước khi ép khuôn hoặc đúc.",
|
||||
"help.inspect.environment_map": "Hiển thị mô hình với lớp hoàn thiện phản chiếu như gương. Dùng để đánh giá độ uôn lượn của bề mặt qua cách các hình phản chiếu chạy trên đó.",
|
||||
"help.inspect.interference": "Tìm các thân khối chồng lấn nhau và hiển thị từng vùng chồng lấn kèm thể tích. Dùng để kiểm tra cụm lắp ráp xem có chi tiết nào va chạm không.",
|
||||
"help.inspect.isocurve": "Vẽ các đường đẳng trị của mặt, tức lưới mà bề mặt được xây dựng trên đó. Dùng để xem bề mặt chạy ra sao và chỗ nào các đường dồn lại.",
|
||||
"help.inspect.measure": "Đo chiều dài, khoảng cách, góc, diện tích và bán kính giữa các đối tượng bạn chọn, hoặc thể tích và khối lượng của thân khối. Dùng để kiểm tra kích thước và khe hở.",
|
||||
"help.inspect.minimum_radius": "Tìm bán kính cong nhỏ nhất của đường cong, cạnh hoặc mặt và vị trí của nó. Dùng để kiểm tra dụng cụ hoặc đầu phun có đi theo được hình dạng này không.",
|
||||
"help.inspect.section": "Cắt mở khung nhìn theo một mặt phẳng và tô gạch các mặt bị cắt, không thay đổi mô hình. Dùng để nhìn vào bên trong chi tiết và cụm lắp ráp.",
|
||||
"help.inspect.zebra": "Hiển thị các sọc đen trắng phản chiếu trên các mặt của mô hình. Dùng để đánh giá độ mượt: sọc bị đứt hoặc gãy tại một cạnh cho thấy chỗ chuyển tiếp kém.",
|
||||
"help.joint.as_built": "Nối hai chi tiết tại vị trí hiện có mà không di chuyển chi tiết nào, đồng thời đặt cách chúng còn có thể chuyển động. Dùng cho các chi tiết đã được đặt ở vị trí cuối cùng.",
|
||||
"help.joint.cam": "Liên kết cam quay với con đội để con đội trượt hoặc lắc khi biên dạng cam đi qua bên dưới. Dùng cho cam, cơ cấu lệch tâm và bộ dẫn động van.",
|
||||
"help.joint.create": "Nối hai chi tiết tại các gốc tọa độ khớp nối bạn chọn và đưa chi tiết thứ hai vào vị trí; loại khớp nối quyết định cách chúng còn có thể chuyển động. Dùng để dựng cụm lắp ráp có các chi tiết chuyển động như cơ cấu thực.",
|
||||
"help.joint.drive": "Đặt góc hoặc khoảng cách của khớp nối và di chuyển các chi tiết theo nó trong giới hạn cho phép; các khớp liên kết và vòng kín chuyển động theo. Dùng để kiểm tra cơ cấu có chuyển động đúng dự kiến hay không.",
|
||||
"help.joint.gear": "Liên kết hai khớp quay theo tỉ số truyền bánh răng để dẫn động khớp này làm khớp kia quay. Dùng cho bánh răng trụ răng thẳng và bánh răng vành, với tỉ số từ bán kính vòng chia hoặc số răng.",
|
||||
"help.joint.limits": "Đặt giới hạn nhỏ nhất và lớn nhất cho góc quay hoặc hành trình trượt của khớp nối, hoặc xóa các giới hạn đó. Dùng để giữ bản lề, con trượt hoặc đòn bẩy trong phạm vi chuyển động thực tế.",
|
||||
"help.joint.motion_link": "Ghép hai khớp nối theo tỉ số và độ lệch để dẫn động khớp này làm khớp kia chuyển động. Dùng cho quan hệ cố định giữa các khớp mà Khớp bánh răng, Khớp thanh răng - bánh răng hoặc Khớp trục vít không đáp ứng.",
|
||||
"help.joint.origin": "Đặt gốc tọa độ khớp nối có tên trên chi tiết: tại tâm mặt hoặc đầu tròn, trung điểm cạnh, góc hoặc một điểm. Dùng để chuẩn bị vị trí gắn khớp nối; gốc chọn trên mặt sẽ đi theo mặt khi chi tiết đổi kích thước.",
|
||||
"help.joint.rack_pinion": "Liên kết bánh răng quay với thanh răng trượt để thanh răng di chuyển bằng độ dài cung vòng chia mà bánh răng lăn qua. Dùng cho bộ truyền thanh răng, cơ cấu lái và bàn trượt tuyến tính.",
|
||||
"help.joint.reach": "Di chuyển một điểm trên chi tiết về phía đích bằng cách thay đổi các khớp trong chuỗi của nó, trong giới hạn cho phép. Dùng để đặt tư thế cơ cấu theo vị trí mong muốn của đầu mút, như đầu cánh tay rô bốt.",
|
||||
"help.joint.rigid_group": "Khóa các chi tiết đã chọn với nhau ở vị trí hiện tại để chúng chuyển động như một khối. Dùng cho các chi tiết thuộc cùng một nhóm và không chuyển động tương đối với nhau.",
|
||||
"help.joint.screw": "Liên kết chuyển động quay và trượt theo bước vít để mỗi vòng quay tiến được khoảng cách đó. Dùng cho vít me, bu lông và trục có ren.",
|
||||
"help.library.apply": "Áp dụng vật liệu hoặc ngoại quan từ tệp thư viện cục bộ lên thân khối, mặt hoặc cụm chi tiết. Dùng để tái sử dụng vật liệu đã lưu từ thiết kế khác.",
|
||||
"help.library.export": "Lưu vật liệu và ngoại quan của thiết kế vào tệp thư viện. Dùng để chia sẻ hoặc tái sử dụng trong các thiết kế khác.",
|
||||
"help.library.inspect": "Kiểm tra một tệp thư viện và liệt kê các vật liệu, ngoại quan trong đó, không thay đổi thiết kế. Dùng để xem thư viện có gì trước khi áp dụng.",
|
||||
"help.licences": "Giấy phép",
|
||||
"help.material.assign": "Đặt vật liệu cho các khối đã chọn, chẳng hạn thép, nhôm hoặc ABS. Dùng để khối lượng và trọng lượng khớp với chi tiết thật.",
|
||||
"help.material.properties.validate": "Kiểm tra thẻ dữ liệu vật liệu xem các số liệu có nhất quán và có thiếu giá trị nào không. Dùng trước khi dựa vào dữ liệu này để tính khối lượng hay độ cứng.",
|
||||
"help.mesh.convert": "Dựng lại thân khối dạng lưới, chẳng hạn tệp STL, thành khối đặc có thể chỉnh sửa với các mặt phẳng và mặt trụ. Dùng để sửa các chi tiết cơ khí nhập vào như một thân khối tự dựng.",
|
||||
"help.mit": "Giấy phép MIT",
|
||||
"help.motion.study": "Đặt giá trị khớp nối tại các bước trên dòng thời gian và phát lại dưới dạng hoạt ảnh. Dùng để quan sát cơ cấu chuyển động theo chuỗi và kiểm tra khe hở trên đường đi.",
|
||||
"help.motion.trace": "Theo dõi quỹ đạo của một điểm trên chi tiết khi phát nghiên cứu chuyển động hoặc dẫn động khớp nối, rồi giữ lại dưới dạng đường cong phác thảo 3D khi xác nhận. Dùng để xem tầm vươn của cơ cấu hoặc dựng hình dựa trên quỹ đạo đó.",
|
||||
"help.notice": "NOTICE",
|
||||
"help.occurrence.ground": "Cố định chi tiết tại chỗ hoặc giải phóng nó trở lại để các khớp nối di chuyển những chi tiết khác quanh nó. Dùng cho khung hoặc đế làm nền cho phần còn lại của cụm lắp ráp.",
|
||||
"help.occurrence.move": "Chỉ di chuyển chi tiết lắp ráp theo các bậc tự do mà khớp nối cho phép. Chọn một mặt của chi tiết, rồi kéo mũi tên hoặc cung tròn có thể sử dụng.",
|
||||
"help.parameters.change": "Mở bảng các giá trị có tên và biểu thức điều khiển kích thước của thiết kế. Dùng để sửa một kích thước ở một chỗ và mọi tính năng dùng nó sẽ cập nhật theo.",
|
||||
"help.parameters.export": "Lưu các tham số của thiết kế dạng CSV hoặc JSON. Dùng để chỉnh sửa trong bảng tính hoặc chuyển sang thiết kế khác.",
|
||||
"help.parameters.graph": "Hiển thị tham số và tính năng nào dùng tham số, tính năng nào khác, cùng các vòng lặp hoặc lỗi giữa chúng. Dùng để biết thay đổi một tham số sẽ ảnh hưởng đến những gì.",
|
||||
"help.parameters.import": "Đọc tham số từ CSV hoặc JSON vào thiết kế, hoặc nhập tất cả hoặc không nhập gì. Dùng để đưa giá trị từ bảng tính hoặc thiết kế khác vào.",
|
||||
"help.parameters.move": "Di chuyển một tham số người dùng lên trước hoặc xuống sau tham số khác trong danh sách. Dùng để giữ các tham số liên quan gần nhau.",
|
||||
"help.parts.fastener": "Thêm vít, bu lông, đai ốc, vòng đệm, chốt hoặc ổ lăn tiêu chuẩn theo kích thước bạn chọn. Dùng tại lỗ để chi tiết liên kết tự lắp vào bằng khớp nối, giúp bạn không phải tự dựng hình chi tiết liên kết.",
|
||||
"help.parts.insert": "Chèn chi tiết tiêu chuẩn theo họ, kích thước và chiều dài bạn chọn. Dùng tại vành hoặc thành lỗ để chi tiết lắp vào lỗ bằng khớp ngàm cứng.",
|
||||
"help.parts.library": "Mở thư viện chi tiết tiêu chuẩn: vít, bu lông, đai ốc, vòng đệm, vít hãm, chốt định vị và ổ lăn theo kích thước tiêu chuẩn. Dùng để thêm chi tiết tiêu chuẩn thay vì tự dựng hình.",
|
||||
"help.parts.resize": "Thay đổi kích thước hoặc chiều dài của chi tiết tiêu chuẩn đã chèn và dựng lại nó; các khớp nối giữ chi tiết đúng vị trí lắp. Dùng khi vít quá dài hoặc lỗ cần kích thước khác.",
|
||||
"help.plastic.assign_rule": "Gán một quy tắc nhựa kỹ thuật cho các thân khối, để các tính năng nhựa của chúng lấy góc thoát khuôn và khe hở từ đó làm mặc định. Dùng để thiết lập chi tiết ép khuôn một lần cho mọi tính năng.",
|
||||
"help.plastic.boss": "Thêm vấu bắt ốc vỏ nhựa lên một mặt: một trụ có thể kèm lỗ, góc thoát khuôn, Bo tròn mép ở chân và các gân tăng cứng. Dùng cho điểm bắt vít trong vỏ ép khuôn hoặc in 3D.",
|
||||
"help.plastic.lip": "Thêm gờ khớp mí hoặc rãnh tương ứng dọc theo mép của thân khối đã khoét rỗng. Dùng để hai nửa vỏ định vị vào nhau và đóng khít.",
|
||||
"help.plastic.manage_rules": "Tạo và chỉnh sửa quy tắc nhựa kỹ thuật: vật liệu, độ dày thành, bán kính, khe hở và góc thoát khuôn. Dùng để các tính năng của chi tiết ép khuôn luôn nhất quán.",
|
||||
"help.plastic.rest": "Thêm vấu đỡ nhựa lên một mặt: đệm tròn hoặc chữ nhật, đặc hoặc rỗng, có góc thoát khuôn. Dùng làm chân đỡ hoặc trụ kê trong vỏ ép khuôn.",
|
||||
"help.plastic.snap_fit": "Thêm móc khớp gài bấm lên một mặt, với chiều dài, độ dày và chốt hãm. Dùng để gài các chi tiết vào nhau mà không cần vít.",
|
||||
"help.pointcloud.insert": "Chèn bản quét PLY, XYZ hoặc PTS dưới dạng đám mây điểm bên cạnh mô hình. Dùng làm tham chiếu khi dựng mô hình từ dữ liệu đo.",
|
||||
"help.sheet.convert": "Biến một tấm hoặc thân khối khoét rỗng có độ dày đều thành thân kim loại tấm, với các chỗ uốn tại cạnh bạn chọn. Dùng để làm cho chi tiết có sẵn trải phẳng được.",
|
||||
"help.sheet.export_bend_table": "Lưu bảng chấn uốn của thân kim loại tấm dạng CSV hoặc JSON: góc, bán kính và vị trí chấn trên bản trải phẳng. Dùng cho máy chấn hoặc xưởng gia công.",
|
||||
"help.sheet.export_dxf": "Lưu bản trải phẳng dạng DXF, gồm đường viền, đường chấn và ghi chú chấn tùy chọn. Dùng cho cắt laser, plasma hoặc tia nước.",
|
||||
"help.sheet.flange": "Thêm chấn gập mép tôn: tấm đế từ phác thảo, thành dọc theo đường viền phác thảo hở, hoặc thành uốn trên cạnh tấm. Dùng để dựng các chi tiết kim loại tấm.",
|
||||
"help.sheet.flat_pattern": "Tạo bản trải phẳng của thân kim loại tấm, gồm kích thước, các lỗ cắt và đường chấn. Dùng để kiểm tra phôi trước khi cắt.",
|
||||
"help.sheet.fold": "Uốn tấm kim loại dọc theo một đường phác thảo với góc và bán kính cho trước. Dùng để gập tấm phẳng sau khi đã tạo các chi tiết cắt trên đó.",
|
||||
"help.sheet.hem": "Gấp mép tấm kim loại ngược lại lên chính nó. Dùng để có mép an toàn, cứng cáp và không còn ba via sắc.",
|
||||
"help.sheet.manage_rules": "Tạo và chỉnh sửa quy tắc kim loại tấm: độ dày, bán kính uốn, K-factor, rãnh giảm ứng suất và khe hở. Dùng để khớp với vật liệu và dụng cụ của xưởng bạn.",
|
||||
"help.sheet.path_flange": "Thêm một chuỗi chấn gập mép tôn dọc theo cạnh tấm, theo một chuỗi đường phác thảo hở. Dùng cho các biên dạng như chữ U hoặc Z chỉ trong một bước.",
|
||||
"help.sheet.perforate": "Thêm một vùng lỗ phủ toàn bộ tấm phẳng, theo kiểu so le hoặc vuông. Dùng cho lỗ thông gió, lưới chắn và tấm nhẹ hơn.",
|
||||
"help.sheet.refold": "Gập lại thân kim loại tấm đã được trải phẳng. Dùng sau khi thêm tính năng lên tấm phẳng.",
|
||||
"help.sheet.unfold": "Trải phẳng mọi chỗ uốn của thân kim loại tấm. Dùng để thêm lỗ hoặc đường cắt phải băng qua chỗ uốn, rồi Gập lại tấm kim loại.",
|
||||
"help.sketch.arc.center_point": "Vẽ cung tròn quanh một tâm, từ điểm đầu đến điểm cuối. Dùng khi đã biết tâm cung, chẳng hạn bán kính quanh lỗ hoặc trục xoay.",
|
||||
"help.sketch.arc.tangent": "Vẽ cung tròn bắt đầu từ đầu mút của đường thẳng hoặc cung và tiếp tuyến với nó. Dùng để nối tiếp chuỗi bằng chỗ uốn mượt thay vì góc nhọn.",
|
||||
"help.sketch.arc.three_point": "Vẽ cung tròn từ điểm đầu đến điểm cuối đi qua điểm thứ ba. Dùng khi cung phải đi qua các điểm cho trước chứ không quanh một tâm đã biết.",
|
||||
"help.sketch.arc3d": "Vẽ cung tròn chính xác trong không gian qua ba điểm, khi bật 3D Phác thảo. Dùng cho các chỗ uốn của đường dẫn và ray dẫn hướng nằm ngoài mặt phẳng phác thảo.",
|
||||
"help.sketch.auto_constrain": "Thêm các ràng buộc mà phác thảo gần như đã thỏa, như nằm ngang, song song hay trùng khớp, rồi thêm kích thước cho đến khi xác định hoàn toàn. Dùng để khóa một phác thảo vẽ tay chỉ trong một bước.",
|
||||
"help.sketch.auto_constrain_from_datum": "Hoạt động như Tự động gán ràng buộc, nhưng đo vị trí từ điểm chuẩn bạn chọn thay vì gốc tọa độ. Dùng khi chi tiết được bố trí từ một điểm tham chiếu, như góc hoặc lỗ.",
|
||||
"help.sketch.blend_curve": "Nối đầu mút của hai đường cong bằng một spline mượt tiếp tuyến với cả hai, hoặc liên tục cả độ cong nếu bạn chọn. Dùng để lấp khoảng hở giữa các đường cong mà không bị gãy.",
|
||||
"help.sketch.break": "Tách đường cong thành các đoạn tại chỗ các đường cong khác cắt qua, hoặc tại các điểm bạn đặt lên nó. Dùng khi một đoạn cần ràng buộc riêng hoặc cần xóa riêng.",
|
||||
"help.sketch.cancel": "Thoát phác thảo và bỏ mọi thay đổi kể từ khi tạo hoặc mở ra để chỉnh sửa. Hoàn tác sẽ khôi phục lại các thay đổi.",
|
||||
"help.sketch.centerline": "Chuyển đường thẳng giữa đường thường và đường tâm, tức trục mà biên dạng bỏ qua. Dùng đường tâm làm trục cho Xoay tròn tạo khối, đối xứng gương hoặc ràng buộc đối xứng.",
|
||||
"help.sketch.chamfer.distance_angle": "Vát mép góc giữa hai đường thẳng theo khoảng cách dọc đường thứ nhất và một góc. Dùng khi bản vẽ cho kích thước vát mép bằng chiều dài và góc, như 2 mm × 30°.",
|
||||
"help.sketch.chamfer.equal_distance": "Vát mép góc giữa hai đường thẳng với cùng khoảng cách dọc theo cả hai. Dùng cho kiểu vát mép 45° thông thường trên đường bao.",
|
||||
"help.sketch.chamfer.two_distance": "Vát mép góc giữa hai đường thẳng với khoảng cách riêng dọc theo từng đường. Dùng cho vát mép không phải 45°, cho bằng hai chiều dài.",
|
||||
"help.sketch.circle.center": "Vẽ đường tròn từ tâm và đường kính. Dùng cho lỗ, vấu và các chi tiết tròn khác đã biết tâm.",
|
||||
"help.sketch.circle.three_point": "Vẽ đường tròn đi qua ba điểm. Dùng khi đường tròn phải đi qua các điểm cho trước, chẳng hạn của hình học có sẵn.",
|
||||
"help.sketch.circle.three_tangent": "Vẽ đường tròn tiếp xúc với ba đường thẳng, đường tròn hoặc cung. Dùng để đặt đường tròn vào khoảng giữa ba đường cong, như đường tròn nội tiếp của tam giác.",
|
||||
"help.sketch.circle.two_point": "Vẽ đường tròn từ hai đầu mút của đường kính. Dùng khi biết các điểm trên mép đường tròn chứ chưa biết tâm.",
|
||||
"help.sketch.circle.two_tangent": "Vẽ đường tròn có kích thước cho trước tiếp xúc với hai đường thẳng, đường tròn hoặc cung. Dùng để bo tròn với bán kính cố định giữa hai đường cong.",
|
||||
"help.sketch.conic": "Vẽ đường conic giữa hai đầu mút, định hình bằng một điểm đỉnh và giá trị rho. Dùng cho các chỗ chuyển tiếp mượt mà bạn muốn chỉnh độ phồng, từ phẳng đến gần như góc nhọn.",
|
||||
"help.sketch.constrainer": "Áp dụng ràng buộc mà một hoặc hai đường cong đã chọn gần như đã thỏa, như nằm ngang, song song, tiếp tuyến hay bằng nhau. Dùng để chỉnh lại phác thảo vẽ tay từng quan hệ một.",
|
||||
"help.sketch.constraint.coincident": "Làm một điểm trùng với điểm khác, nằm trên một đường cong hoặc trục phác thảo. Dùng để đóng khe hở trong biên dạng hoặc đặt điểm lên đường thẳng.",
|
||||
"help.sketch.constraint.collinear": "Làm hai đường thẳng nằm trên cùng một đường thẳng. Dùng để căn thẳng hàng các cạnh bị ngắt quãng, như hai bên của một khe khuyết.",
|
||||
"help.sketch.constraint.concentric": "Cho hai đường tròn hoặc cung cùng một tâm. Dùng cho vòng, lỗ khoét bậc và trục có vai.",
|
||||
"help.sketch.constraint.curvature": "Làm hai đường cong gặp nhau tại đầu mút tiếp tục với cùng độ cong (G2). Dùng khi nối tiếp tuyến chưa đủ mượt, chẳng hạn trên các bề mặt nhìn thấy.",
|
||||
"help.sketch.constraint.equal": "Làm các đường thẳng bằng chiều dài, hoặc các đường tròn và cung bằng bán kính. Dùng để một kích thước điều khiển nhiều chi tiết giống nhau.",
|
||||
"help.sketch.constraint.fix": "Cố định điểm hoặc đường cong tại chỗ, hoặc bỏ cố định chúng. Dùng cho hình học không được di chuyển khi bạn kéo hoặc giải phác thảo.",
|
||||
"help.sketch.constraint.horizontal_vertical": "Làm một đường thẳng, hoặc đường nối hai điểm, nằm ngang hoặc thẳng đứng, tùy hướng nào gần hơn. Dùng để căn đường bao thẳng theo các trục phác thảo.",
|
||||
"help.sketch.constraint.midpoint": "Đặt một điểm vào trung điểm của đường thẳng, hoặc làm trung điểm của hai đường thẳng trùng nhau. Dùng để căn giữa hình học trên một cạnh.",
|
||||
"help.sketch.constraint.parallel": "Làm hai đường thẳng song song. Dùng cho các cạnh phải luôn song song khi các kích thước khác thay đổi.",
|
||||
"help.sketch.constraint.perpendicular": "Làm hai đường thẳng gặp nhau ở góc vuông. Dùng cho các góc vuông giữa những đường không nằm trên trục phác thảo.",
|
||||
"help.sketch.constraint.polygon": "Biến chuỗi đường thẳng khép kín thành đa giác đều: các cạnh bằng nhau, mọi đỉnh nằm trên một đường tròn. Dùng để làm đa giác vẽ tay thành đa giác đều và giữ nguyên như vậy.",
|
||||
"help.sketch.constraint.symmetry": "Làm hai điểm hoặc đường cong đối xứng nhau qua một đường thẳng hoặc quanh một điểm. Dùng để giữ biên dạng đối xứng khi bạn sửa một bên.",
|
||||
"help.sketch.constraint.tangent": "Làm hai đường cong tiếp xúc tiếp tuyến, như đường thẳng và cung. Dùng cho các chỗ nối mượt, không bị gãy góc.",
|
||||
"help.sketch.construction": "Chuyển đường cong giữa hình học thường và hình học dựng hình, thứ mà biên dạng bỏ qua. Dùng đường dựng hình làm công cụ hỗ trợ bố trí, tham chiếu và ghi kích thước.",
|
||||
"help.sketch.construction_line": "Tạo đường thẳng dựng hình vô hạn qua hai điểm để bố trí phác thảo mà không chia tách biên dạng.",
|
||||
"help.sketch.construction_line.angle": "Tạo đường dựng hình vô hạn theo góc so với trục X của phác thảo. Chọn điểm rồi nhập góc hoặc chọn hướng.",
|
||||
"help.sketch.construction_line.bisector": "Chọn hai đường thẳng giao nhau trong phác thảo rồi chọn một trong hai đường phân giác. Kết quả thay đổi theo các đường gốc.",
|
||||
"help.sketch.construction_line.horizontal": "Tạo đường dựng hình nằm ngang vô hạn qua một điểm. Ràng buộc ngang được giữ khi chỉnh sửa sau này.",
|
||||
"help.sketch.construction_line.parallel": "Chọn đường thẳng trong phác thảo rồi đặt đường dựng hình vô hạn song song. Nhấp chuột phải để đổi tham chiếu.",
|
||||
"help.sketch.construction_line.perpendicular": "Chọn đường thẳng trong phác thảo rồi đặt đường dựng hình vô hạn vuông góc. Nhấp chuột phải để đổi tham chiếu.",
|
||||
"help.sketch.construction_line.tangent_at": "Tạo tiếp tuyến tại một điểm trên đường tròn hoặc cung tròn, hoặc tại đầu mút của spline hay đường conic hở. Chọn đường cong rồi chọn tiếp điểm.",
|
||||
"help.sketch.construction_line.tangent_external": "Chọn đường tròn hoặc cung tròn, một điểm ngoài rồi chọn nghiệm tiếp tuyến. Bản xem trước chỉ hiển thị tiếp điểm trên cung đã vẽ.",
|
||||
"help.sketch.construction_line.tangent_two": "Chọn hai đường tròn hoặc cung tròn rồi chọn tiếp tuyến chung trong bản xem trước. Tiếp điểm phải nằm trên các đường cong đã vẽ.",
|
||||
"help.sketch.construction_line.vertical": "Tạo đường dựng hình thẳng đứng vô hạn qua một điểm. Ràng buộc đứng được giữ khi chỉnh sửa sau này.",
|
||||
"help.sketch.copy": "Sao chép các đường cong và điểm phác thảo đã chọn, cùng các ràng buộc và kích thước giữa chúng. Dán vào phác thảo này hoặc phác thảo khác.",
|
||||
"help.sketch.create": "Bắt đầu một phác thảo 2D mới trên mặt phẳng chuẩn hoặc mặt phẳng của khối. Mọi lệnh Đùn khối, Xoay tròn tạo khối và Quét theo đường dẫn đều bắt đầu từ một phác thảo.",
|
||||
"help.sketch.cut": "Sao chép hình học phác thảo đã chọn rồi xóa khỏi phác thảo, trong một bước hoàn tác. Dán sang chỗ khác trong phác thảo này hoặc phác thảo khác.",
|
||||
"help.sketch.dimension": "Thêm kích thước điều khiển: chiều dài, khoảng cách, góc, bán kính hoặc đường kính, tùy thứ bạn chọn. Nhập giá trị hoặc tên tham số, phác thảo sẽ thay đổi theo.",
|
||||
"help.sketch.edit": "Mở một phác thảo có sẵn để chỉnh sửa. Các tính năng dựng trên nó sẽ cập nhật khi bạn hoàn tất phác thảo.",
|
||||
"help.sketch.ellipse": "Vẽ hình elip từ tâm, đầu mút trục lớn và một điểm ở phía trục nhỏ. Dùng cho lỗ mở hình bầu dục, cam và các hình tròn dài khác.",
|
||||
"help.sketch.equation_curve": "Vẽ một đường cong từ công thức trên một khoảng: x(t) và y(t), hoặc y = f(x). Công thức có thể dùng tham số và đường cong thay đổi theo: dùng cho sóng sin, đường xoắn ốc hay đường thân khai của răng bánh răng.",
|
||||
"help.sketch.extend": "Kéo dài đường thẳng hoặc cung đến đường cong gần nhất cản đường, hoặc kéo hai đường cong cho đến khi gặp nhau. Dùng để đóng khe hở trong biên dạng sau khi cắt tỉa hoặc chỉnh sửa.",
|
||||
"help.sketch.fillet": "Bo tròn góc nơi hai đường thẳng hoặc cung gặp nhau bằng một cung có bán kính cho trước. Nhiều góc bo cùng lúc dùng chung một bán kính.",
|
||||
"help.sketch.finish": "Thoát phác thảo và quay lại mô hình. Các biên dạng khép kín của nó khi đó sẵn sàng cho Đùn khối, Xoay tròn tạo khối và các tính năng khác.",
|
||||
"help.sketch.finish_auto_constrain": "Chạy Tự động gán ràng buộc cho phác thảo rồi hoàn tất. Dùng để để lại phác thảo xác định hoàn toàn chỉ trong một bước.",
|
||||
"help.sketch.fit_curves_to_section": "Cắt một lưới hoặc khối đặc bằng mặt phẳng phác thảo rồi khớp các đường thẳng và cung vào mặt cắt. Dùng để dựng lại chi tiết quét hoặc nhập vào thành phác thảo có thể chỉnh sửa.",
|
||||
"help.sketch.include_3d": "Đưa cạnh, đỉnh của mô hình và đường cong của các phác thảo khác vào phác thảo này dưới dạng tham chiếu liên kết, làm phẳng phần nằm ngoài mặt phẳng của nó. Dùng để dựng tiếp trên hình học không nằm trong mặt phẳng phác thảo.",
|
||||
"help.sketch.infinite": "Chuyển đường thẳng giữa đường thường và đường dựng hình vô hạn chạy suốt khung nhìn. Dùng làm tham chiếu bố trí không bao giờ bị ngắn.",
|
||||
"help.sketch.insert_dxf": "Đọc các đường cong của bản vẽ DXF vào phác thảo, theo tỉ lệ, góc xoay và vị trí bạn đặt. Dùng để dựng tiếp từ bản vẽ 2D của chương trình khác, như biên dạng cắt laser.",
|
||||
"help.sketch.insert_svg": "Đọc các đường dẫn của bản vẽ SVG vào phác thảo, theo tỉ lệ, góc xoay và vị trí bạn đặt. Dùng để biến logo hoặc đường bao véc tơ thành đường cong có thể đùn.",
|
||||
"help.sketch.inspect": "Mở báo cáo về bản phác thảo đang mở: còn bao nhiêu bậc tự do và đã ràng buộc hoàn toàn chưa. Dùng nó để biết phần nào vẫn còn di chuyển được trước khi hoàn tất bản phác thảo.",
|
||||
"help.sketch.intersect": "Thêm các đường cong hoặc điểm nơi khối, mặt, cạnh hoặc phác thảo khác cắt qua mặt phẳng phác thảo. Chúng vẫn được liên kết và thay đổi theo mô hình.",
|
||||
"help.sketch.intersection_curve": "Tạo đường cong 3D tại nơi hai khối hoặc hai mặt gặp nhau, liên kết với chúng. Dùng làm đường dẫn hoặc ray dẫn hướng thay đổi theo mô hình.",
|
||||
"help.sketch.isoparametric_curve": "Tạo đường cong 3D theo hướng U hoặc V của một mặt qua điểm bạn chọn, liên kết với mặt đó. Dùng làm đường dẫn hoặc đường tách thay đổi theo bề mặt.",
|
||||
"help.sketch.line": "Vẽ các đường thẳng nối liền từng điểm một, thành chuỗi hở hoặc đường bao khép kín. Đây là công cụ cơ bản cho hầu hết biên dạng.",
|
||||
"help.sketch.line.midpoint": "Vẽ đường thẳng từ trung điểm ra một đầu, đầu kia đối xứng qua trung điểm. Dùng cho đường thẳng có tâm tại một điểm, như cạnh đối xứng.",
|
||||
"help.sketch.line3d": "Vẽ các đường thẳng nối giữa các điểm trong không gian, khi bật 3D Phác thảo. Dùng cho đường dẫn và khung nằm ngoài mặt phẳng phác thảo.",
|
||||
"help.sketch.mirror": "Lấy đối xứng gương các đường cong và điểm phác thảo qua một đường thẳng hoặc trục, đồng thời thêm ràng buộc đối xứng. Dùng để vẽ nửa biên dạng đối xứng rồi hoàn thiện nó.",
|
||||
"help.sketch.move": "Di chuyển hoặc xoay các đường cong và điểm phác thảo, hoặc một bản sao của chúng. Dùng để đổi vị trí hình học mà vẫn giữ nguyên hình dạng và ràng buộc.",
|
||||
"help.sketch.offset": "Tạo bản sao của một chuỗi đường cong ở khoảng cách cho trước, về một phía hoặc cả hai. Dùng cho thành, đường bao và khe hở; khoảng cách vẫn là kích thước có thể chỉnh sửa.",
|
||||
"help.sketch.paste": "Dán hình học phác thảo đã sao chép hoặc cắt vào phác thảo đang hoạt động. Đặt tại một điểm hoặc dời theo một khoảng.",
|
||||
"help.sketch.pattern.circular": "Sao chép hình học phác thảo quanh một tâm, trên cả vòng tròn hoặc một góc cho trước. Dùng cho vòng lỗ bu lông, nan hoa và răng.",
|
||||
"help.sketch.pattern.rectangular": "Sao chép hình học phác thảo theo hàng và cột với khoảng cách cho trước. Dùng cho lưới lỗ, rãnh then hoặc khe thông gió.",
|
||||
"help.sketch.point": "Đặt một điểm phác thảo. Dùng làm tham chiếu cho kích thước, ràng buộc, tâm lỗ hoặc các tính năng sau này.",
|
||||
"help.sketch.point3d": "Đặt một điểm trong không gian, khi bật 3D Phác thảo. Dùng làm tham chiếu cho đường cong và đường dẫn 3D.",
|
||||
"help.sketch.polygon.circumscribed": "Vẽ đa giác đều bao quanh một đường tròn, kích thước tính từ tâm đến trung điểm một cạnh. Dùng khi biết khoảng cách giữa hai cạnh đối diện, như với đai ốc lục giác.",
|
||||
"help.sketch.polygon.edge": "Vẽ đa giác đều từ hai đầu mút của một cạnh. Dùng khi biết chiều dài và vị trí của cạnh.",
|
||||
"help.sketch.polygon.inscribed": "Vẽ đa giác đều nội tiếp trong một đường tròn, kích thước tính từ tâm đến một đỉnh. Dùng khi biết kích thước giữa hai đỉnh đối diện.",
|
||||
"help.sketch.project": "Đưa cạnh, mặt, đỉnh của mô hình và đường cong của các phác thảo khác vào phác thảo này, chiếu lên mặt phẳng của nó. Chúng vẫn được liên kết và thay đổi theo mô hình.",
|
||||
"help.sketch.project_to_surface": "Chiếu đường cong của các phác thảo khác theo pháp tuyến của phác thảo này lên một mặt, thành đường cong 3D liên kết. Dùng để đặt logo, đường tách hoặc đường dẫn lên bề mặt cong.",
|
||||
"help.sketch.rectangle.center": "Vẽ hình chữ nhật từ tâm và một góc. Dùng cho đường bao có tâm tại một điểm, như gốc tọa độ.",
|
||||
"help.sketch.rectangle.rounded": "Vẽ hình chữ nhật có cả bốn góc bo tròn cùng một bán kính. Dùng cho tấm, nắp và lỗ mở có góc bo tròn.",
|
||||
"help.sketch.rectangle.three_point": "Vẽ hình chữ nhật từ một cạnh và một điểm ở phía đối diện. Dùng cho hình chữ nhật nghiêng so với trục phác thảo.",
|
||||
"help.sketch.rectangle.two_point": "Vẽ hình chữ nhật từ hai góc đối diện. Dùng cho đường bao của tấm, khối và hốc.",
|
||||
"help.sketch.scale": "Thay đổi tỉ lệ các đường cong và điểm phác thảo theo một hệ số quanh điểm gốc. Dùng để đổi kích thước một phần phác thảo mà không phải vẽ lại.",
|
||||
"help.sketch.slot.arc_center": "Vẽ rãnh then cong có độ rộng cho trước dọc theo một cung xác định bởi tâm, điểm đầu và điểm cuối. Dùng cho rãnh điều chỉnh quanh trục xoay.",
|
||||
"help.sketch.slot.arc_three_point": "Vẽ rãnh then cong có độ rộng cho trước dọc theo một cung đi qua ba điểm. Dùng khi đường đi của rãnh phải qua các điểm cho trước.",
|
||||
"help.sketch.slot.center_point": "Vẽ rãnh then thẳng có độ rộng cho trước từ tâm của nó đến tâm cung ở một đầu. Dùng cho rãnh có tâm tại một điểm.",
|
||||
"help.sketch.slot.center_to_center": "Vẽ rãnh then thẳng có độ rộng cho trước giữa tâm của hai cung ở hai đầu. Dùng cho rãnh ghi kích thước tâm đến tâm, như rãnh điều chỉnh vít.",
|
||||
"help.sketch.slot.overall": "Vẽ rãnh then thẳng có độ rộng cho trước từ mép ngoài này đến mép ngoài kia. Dùng khi chiều dài toàn phần của rãnh là điều quan trọng.",
|
||||
"help.sketch.spline.control_point": "Vẽ spline bậc ba được định hình bởi các điểm điều khiển mà nó không đi qua. Dùng cho đường cong mượt, uyển chuyển mà bạn chỉnh bằng cách di chuyển các điểm.",
|
||||
"help.sketch.spline.control_point_5": "Vẽ spline bậc 5 được định hình bởi các điểm điều khiển. Dùng khi các đường cong cần nối với độ cong mượt hơn, chẳng hạn trên bề mặt tạo dáng nhìn thấy.",
|
||||
"help.sketch.spline.fit_point": "Vẽ spline mượt đi qua mọi điểm bạn đặt, hở hoặc khép kín. Dùng để vẽ theo một hình dạng qua các điểm đã biết.",
|
||||
"help.sketch.spline3d": "Vẽ đường cong mượt trong không gian qua các điểm, khi bật 3D Phác thảo. Dùng cho đường dẫn của lệnh Quét theo đường dẫn và đường đi dây cáp nằm ngoài mặt phẳng phác thảo.",
|
||||
"help.sketch.spun_profile": "Tạo trong mặt phẳng phác thảo đường bao mà một khối quét qua khi quay quanh một trục. Dùng để lấy hình bóng của chi tiết tiện cho lệnh Xoay tròn tạo khối hoặc bản vẽ.",
|
||||
"help.sketch.text": "Viết văn bản trong phác thảo với phông chữ, chiều cao và góc tùy chọn; nội dung có thể thay đổi theo tham số. Dùng Đùn khối hoặc Dập nổi để làm nhãn và chữ.",
|
||||
"help.sketch.transform": "Đổi tỉ lệ, xoay và di chuyển hình học phác thảo quanh một tâm chỉ trong một bước. Dùng để đổi vị trí và kích thước của vùng chọn cùng lúc.",
|
||||
"help.sketch.trim": "Xóa đoạn đường cong nằm giữa các giao điểm gần nhất quanh chỗ bạn nhấp. Dùng để dọn các đường chồng lên nhau thành biên dạng khép kín.",
|
||||
"help.solid.align": "Di chuyển các khối đã chọn để một điểm, mặt hoặc mặt phẳng trên chúng gặp một điểm, mặt hoặc mặt phẳng ở nơi khác. Dùng để đặt chi tiết áp vào chi tiết khác mà không cần đo khoảng cách.",
|
||||
"help.solid.boundary_fill": "Tạo khối đặc từ các vùng được bao kín bởi các thân khối công cụ chồng lấn, chỉ điền đầy những vùng bạn chọn. Dùng để dựng hình từ không gian được nhiều thân khối cùng bao lại.",
|
||||
"help.solid.bounding_solid": "Tạo khối hộp bao ngoài các thân khối đã chọn, có thể thêm khoảng dư. Dùng để xem kích thước tổng thể của chi tiết hoặc làm phôi để gia công chi tiết đó.",
|
||||
"help.solid.box": "Tạo khối hộp theo chiều dài, chiều rộng và chiều cao, từ điểm góc hoặc có tâm tại một điểm. Dùng để tạo nhanh khối, hình giữ chỗ hoặc thân khối để cắt tạo các tính năng.",
|
||||
"help.solid.chamfer": "Vát các cạnh đã chọn theo khoảng cách bạn thiết lập. Dùng để triệt tiêu cạnh sắc hoặc giúp lắp chốt, bu lông dễ dàng hơn.",
|
||||
"help.solid.coil": "Tạo thân khối xoắn ốc, như lò xo, từ đường kính, số vòng, chiều cao hoặc bước xoắn và tiết diện tròn hoặc vuông. Dùng cho lò xo, cuộn xoắn và gờ xoắn ốc.",
|
||||
"help.solid.combine": "Hợp nhất các khối, cắt trừ khỏi khối đích, hoặc chỉ giữ lại phần thể tích giao nhau, đồng thời có thể giữ lại các khối công cụ. Dùng để gộp chi tiết, dùng hình này cắt hình kia hoặc tìm vị trí hai khối giao nhau.",
|
||||
"help.solid.cone": "Tạo khối nón từ đường tròn đáy và chiều cao, hoặc nón cụt khi đỉnh cũng có bán kính. Dùng cho phần thuôn, phễu, lỗ loe côn và đầu nhọn.",
|
||||
"help.solid.cylinder": "Tạo khối trụ theo bán kính hoặc đường kính và chiều cao, dựng tại một điểm dọc theo một trục. Dùng cho trục, chốt, vấu trụ và phôi tròn.",
|
||||
"help.solid.draft": "Làm nghiêng các mặt đã chọn theo góc thiết lập, đo từ một mặt phẳng trung hòa. Dùng cho chi tiết đúc hoặc ép phun để chúng tháo ra khỏi khuôn được.",
|
||||
"help.solid.emboss": "Dập nổi các biên dạng phác thảo, như chữ hoặc logo, lên khỏi mặt hoặc dập chìm vào mặt. Dùng cho chữ, nhãn và dấu trên mặt phẳng hoặc mặt tròn.",
|
||||
"help.solid.extrude": "Đùn biên dạng phác thảo thành khối 3D theo khoảng cách, thêm hoặc bớt vật liệu. Dùng để biến phác thảo phẳng thành khối, vấu nổi hoặc hốc lõm.",
|
||||
"help.solid.fillet": "Bo tròn các cạnh đã chọn bằng cung cong mượt mà theo bán kính thiết lập. Dùng để làm mềm cạnh sắc nhằm tăng độ bền, an toàn khi chạm hoặc tăng thẩm mỹ.",
|
||||
"help.solid.hole": "Khoan lỗ tròn theo đường kính thiết lập tại vị trí chọn trên mặt. Dùng cho lỗ xỏ bu lông, chốt định vị và các lỗ tròn đơn giản.",
|
||||
@@ -1402,20 +1644,60 @@
|
||||
"help.solid.move": "Di chuyển hoặc xoay các khối đã chọn, hoặc một bản sao của chúng, theo khoảng cách và góc thiết lập. Dùng để đổi vị trí một khối hoặc tạo thêm một khối ở chỗ khác.",
|
||||
"help.solid.offset_face": "Đẩy các mặt đã chọn vào trong hoặc ra ngoài theo khoảng cách thiết lập, các mặt xung quanh tự điều chỉnh theo. Dùng để làm thành dày hơn, hốc sâu hơn hoặc phần lồi cao hơn mà không sửa bản phác thảo.",
|
||||
"help.solid.pattern.circular": "Lặp lại các đối tượng được chọn quanh một trục theo số lượng và tổng góc thiết lập. Dùng cho bố trí vòng bu lông, nan hoa, cánh tản nhiệt và răng bánh răng.",
|
||||
"help.solid.pattern.path": "Sao chép tính năng hoặc thân khối dọc theo đường phác thảo, theo số lượng và khoảng cách. Dùng cho các lỗ dọc theo cạnh cong hoặc chi tiết dọc theo thanh ray.",
|
||||
"help.solid.pattern.rectangular": "Lặp lại các đối tượng được chọn theo một hoặc hai hướng với số lượng và khoảng cách thiết lập. Dùng cho dãy hoặc mảng lỗ, gân tăng cứng, chốt định vị hoặc chân đế.",
|
||||
"help.solid.pipe": "Tạo ống tròn dọc theo đường dẫn gồm các đường cong phác thảo, đặc hoặc rỗng với độ dày thành. Dùng cho ống, dây điện, cáp và thanh ray.",
|
||||
"help.solid.press_pull": "Thêm hoặc bớt vật liệu khi kéo một mặt, hoặc bo tròn các cạnh khi kéo chúng. Dùng để sửa nhanh trực tiếp trên mô hình.",
|
||||
"help.solid.remove": "Loại các khối đã chọn khỏi thiết kế từ điểm này trong lịch sử trở đi; các bước trước vẫn giữ chúng. Dùng để bỏ một khối phụ trợ, như một công cụ cắt không còn cần.",
|
||||
"help.solid.replace_face": "Đưa các mặt phẳng đã chọn tới một mặt phẳng hoặc một mặt song song, khối sẽ dài ra hoặc ngắn lại để chạm tới đó. Dùng để làm một mặt phẳng hàng với chi tiết khác hoặc với mặt phẳng dựng hình.",
|
||||
"help.solid.revolve": "Quay biên dạng phác thảo quanh một trục để tạo khối tròn xoay. Dùng cho trục, núm xoay, chén bát và bất kỳ chi tiết nào tròn xoay quanh tâm.",
|
||||
"help.solid.rib": "Thêm gân tăng cứng mỏng dọc theo đường cong phác thảo hở, kéo đầy tới các mặt kế tiếp của thân khối. Dùng để tăng cứng thành và góc, chẳng hạn trong chi tiết đúc hoặc in.",
|
||||
"help.solid.scale": "Phóng to hoặc thu nhỏ các khối đã chọn theo một hệ số, như nhau theo mọi hướng hoặc riêng cho từng trục. Dùng để đổi kích thước hình nhập vào hoặc bù độ co ngót.",
|
||||
"help.solid.shell": "Khoét rỗng khối đặc, để lại thành mỏng theo độ dày thiết lập, và có thể mở các mặt bạn chọn. Dùng cho hộp, nắp che và các chi tiết thành mỏng.",
|
||||
"help.solid.sphere": "Tạo khối cầu theo bán kính hoặc đường kính quanh một điểm tâm. Dùng cho bi, núm và đầu bo tròn.",
|
||||
"help.solid.split_body": "Tách một khối thành các khối riêng bằng một mặt phẳng, mặt của khối khác hoặc một đường thẳng trong bản phác thảo. Dùng để tạo các chi tiết được in, gia công hoặc tô màu riêng.",
|
||||
"help.solid.split_face": "Chia các mặt đã chọn theo một mặt phẳng, mặt của khối khác hoặc các đường cong phác thảo, mà không tách khối. Dùng để cho một phần của mặt có độ nghiêng, màu hoặc độ dịch riêng.",
|
||||
"help.solid.sweep": "Quét một biên dạng phác thảo dọc theo đường dẫn để tạo khối đặc. Dùng cho đường ống, thanh ray, tay vịn và bất kỳ chi tiết nào có tiết diện không đổi chạy dọc theo đường cong.",
|
||||
"help.solid.thread": "Thêm ren hệ mét ISO lên mặt trụ, dưới dạng ren biểu diễn hoặc cắt vào thân khối. Dùng cho bu lông, lỗ ren và các chi tiết ren được in.",
|
||||
"help.solid.torus": "Tạo khối vòng từ bán kính lớn quanh trục và bán kính nhỏ của tiết diện tròn. Dùng cho vòng đệm kín, tay cầm và gờ tròn dạng vòng.",
|
||||
"help.solid.web": "Thêm thành mỏng dọc theo mỗi đường cong phác thảo hở, mỗi thành kéo đầy tới các mặt kế tiếp của thân khối. Dùng để tạo mạng lưới gân đỡ bên trong vỏ hộp và khay.",
|
||||
"help.surface.blend": "Tạo mặt cong nối các cạnh của hai thân khối, tiếp tuyến hoặc liên tục độ cong với cả hai. Dùng để nối hai mặt cong mượt qua một khoảng hở.",
|
||||
"help.surface.boundary": "Tạo mặt cong lấp đầy một vòng gồm hai đến bốn đường cong phác thảo, hoặc một mạng đường cong. Dùng cho các tấm tự do được xác định bởi các cạnh của chúng.",
|
||||
"help.surface.extend": "Kéo dài mặt cong ra ngoài cạnh của nó, theo khoảng cách hoặc đến một mặt phẳng hoặc mặt. Dùng để các mặt cong chồng lên nhau trước khi Cắt tỉa hoặc Khâu mặt cong (Stitch).",
|
||||
"help.surface.extrude": "Đùn các đường cong hoặc biên dạng phác thảo theo một khoảng cách thành mặt cong, chỉ có thành, không có nắp. Dùng cho thành mỏng và làm dụng cụ cắt hoặc tách.",
|
||||
"help.surface.fair": "Làm mượt phần bên trong của các mặt tự do trong khi cạnh của chúng giữ nguyên. Dùng để san phẳng các chỗ lồi lõm và phản chiếu gợn sóng trên bề mặt.",
|
||||
"help.surface.loft": "Tạo mặt cong đi qua hai hoặc nhiều tiết diện theo thứ tự, không có nắp. Dùng cho vỏ mỏng và chuyển tiếp giữa các hình dạng khác nhau.",
|
||||
"help.surface.match": "Dựng lại cạnh của một mặt cong để gặp cạnh của thân khối khác, khớp tiếp tuyến hoặc độ cong. Dùng để khép kín đường nối mượt giữa hai mặt cong.",
|
||||
"help.surface.offset": "Tạo bản sao của các mặt cách một khoảng theo pháp tuyến, thành một thân mặt cong mới. Dùng để tạo lớp vỏ, khe hở hoặc mặt bên kia của một thành.",
|
||||
"help.surface.patch": "Lấp một vùng phác thảo hoặc vòng cạnh kín bằng một mặt, phẳng hoặc cong mượt. Dùng để bít các lỗ trên thân mặt cong.",
|
||||
"help.surface.reverse_normal": "Lật các mặt của thân mặt cong để phía ngoài của chúng quay sang hướng ngược lại. Dùng trước khi Tạo độ dày cho mặt cong hoặc Khâu mặt cong (Stitch) khi các mặt đang hướng vào trong.",
|
||||
"help.surface.revolve": "Xoay các đường cong hoặc biên dạng phác thảo quanh một trục thành mặt cong, không có nắp. Dùng cho vỏ tròn như chụp đèn, bát và vòi phun.",
|
||||
"help.surface.ruled": "Tạo một dải đường thẳng xuất phát từ chuỗi cạnh, theo pháp tuyến, tiếp tuyến của mặt hoặc theo một góc. Dùng cho thành thoát khuôn, vùng thoát và mặt phân khuôn.",
|
||||
"help.surface.stitch": "Khâu các thân mặt cong lại với nhau dọc theo cạnh chung, thành khối đặc nếu chúng khép kín. Dùng để biến một tập hợp mặt cong thành một thân khối.",
|
||||
"help.surface.sweep": "Di chuyển các đường cong hoặc biên dạng phác thảo dọc theo đường dẫn để tạo mặt cong, không có nắp. Dùng cho máng xối, nẹp viền và các hình mỏng khác chạy theo đường dẫn.",
|
||||
"help.surface.thicken": "Cho thân mặt cong một độ dày, biến nó thành khối đặc. Dùng để tạo chi tiết in được hoặc gia công được từ các mặt cong.",
|
||||
"help.surface.trim": "Cắt một mặt cong bằng mặt phẳng, mặt cong khác hoặc đường cong phác thảo, và giữ lại phía bạn chọn. Dùng để cắt tỉa các mặt cong theo hình trước khi Khâu mặt cong (Stitch).",
|
||||
"help.surface.unstitch": "Tách các mặt của một thân khối thành những thân mặt cong riêng; khối đặc sẽ rã ra thành các mặt cong. Dùng để chỉnh lại từng mặt riêng của một thân khối.",
|
||||
"help.surface.untrim": "Loại bỏ các lỗ khỏi một mặt, hoặc khôi phục biên ngoài của nó về giới hạn tự nhiên của mặt cong. Dùng để lấy lại toàn bộ mặt cong sau khi Cắt tỉa.",
|
||||
"help.third_party": "Giấy phép của bên thứ ba",
|
||||
"help.timeline.compute_all": "Dựng lại mọi tính năng trong lịch sử từ đầu. Dùng để làm mới mô hình và xem tính năng nào bị lỗi.",
|
||||
"help.timeline.delete": "Xóa các tính năng đã chọn khỏi lịch sử; xóa một bản phác thảo cũng xóa các tính năng dựng từ nó. Dùng để bỏ một bước không còn cần.",
|
||||
"help.timeline.dependents": "Liệt kê các tính năng sẽ bị xóa cùng một tính năng, và những tính năng sẽ lỗi nếu thiếu nó. Dùng trước khi xóa hoặc thay đổi một tính năng.",
|
||||
"help.timeline.play": "Phát lại lần lượt các tính năng còn lại, tạm dừng nửa giây sau mỗi lần dựng lại. Chạy lại lệnh này hoặc nhấn Escape để dừng; Đến cuối sẽ chuyển ngay đến cuối lịch sử.",
|
||||
"help.view.apply": "Xoay khung nhìn về hướng chuẩn như trước, trên hoặc iso, hoặc về một góc nhìn đã lưu. Dùng để xem mô hình từ một góc cố định.",
|
||||
"help.view.delete": "Xóa một góc nhìn đã lưu. Mô hình không bị thay đổi.",
|
||||
"help.view.fit": "Phóng to và dịch khung nhìn để toàn bộ mô hình, hoặc phần đang chọn, lấp đầy khung nhìn. Dùng khi mô hình đã trôi ra khỏi tầm mắt.",
|
||||
"help.view.grid": "Hiện hoặc ẩn lưới trong khung nhìn. Dùng làm thước tham chiếu kích thước và hướng khi dựng mô hình.",
|
||||
"help.view.ground_shadow": "Hiện hoặc ẩn bóng của mô hình trên mặt sàn. Dùng để đánh giá độ cao và vị trí dễ hơn.",
|
||||
"help.view.home": "Đưa khung nhìn về hướng mặc định và vừa khít mô hình. Dùng để quay lại nhanh một góc nhìn quen thuộc.",
|
||||
"help.view.list": "Liệt kê các góc nhìn đã lưu trong thiết kế. Dùng để tìm góc nhìn bạn đã lưu trước đó.",
|
||||
"help.view.navigate": "Xoay, dịch hoặc thu phóng khung nhìn theo từng bước, chẳng hạn xoay một phần tư vòng sang trái. Dùng để điều khiển camera chính xác thay vì kéo chuột.",
|
||||
"help.view.navigation_bar": "Hiện hoặc ẩn thanh điều hướng ở cuối khung nhìn. Ẩn đi để có thêm chỗ, hiện ra để dùng các công cụ xem bằng chuột.",
|
||||
"help.view.rename": "Đặt tên mới cho một góc nhìn đã lưu. Bản thân góc nhìn không đổi.",
|
||||
"help.view.save": "Lưu vị trí camera hiện tại thành một góc nhìn có tên trong thiết kế. Dùng để quay lại đúng góc đó sau này, chẳng hạn khi chụp ảnh màn hình.",
|
||||
"help.view.spin": "Quay khung nhìn quanh mô hình liên tục cho đến cú nhấp hoặc phím tiếp theo. Dùng để trình bày mô hình từ mọi phía.",
|
||||
"help.view.tool": "Giữ cố định một công cụ camera (xoay quanh, dịch hoặc thu phóng) để kéo bằng nút chuột trái sẽ di chuyển khung nhìn cho đến khi bạn tắt nó. Dùng trên bàn di chuột hoặc khi không có nút chuột giữa.",
|
||||
"help.view.visual_style": "Đổi cách vẽ mô hình: tô bóng có hoặc không có cạnh, khung dây, hoặc hiện cạnh khuất. Dùng khung dây để nhìn vào bên trong, tô bóng để có hình ảnh gọn gàng.",
|
||||
"history.sketch_under_constrained": "Thiếu ràng buộc ({count} bậc tự do)",
|
||||
"history.sketch_under_constrained_one": "Thiếu ràng buộc ({count} bậc tự do)",
|
||||
"hole_presets.confirm_delete": "Xác nhận xóa",
|
||||
@@ -1592,6 +1874,10 @@
|
||||
"material.selection.mixed": "Các vật liệu khác nhau",
|
||||
"measure.at": "Tại",
|
||||
"measure.item": "Mục {number}",
|
||||
"measure.quick_copied": "Đã sao chép số đo",
|
||||
"measure.quick_copy": "Nhấp để sao chép số đo",
|
||||
"measure.quick_edges": "{count} cạnh",
|
||||
"measure.quick_faces": "{count} mặt",
|
||||
"messages.ago_h": "{n} giờ trước",
|
||||
"messages.ago_min": "{n} phút trước",
|
||||
"messages.ago_s": "{n} giây trước",
|
||||
@@ -1625,6 +1911,7 @@
|
||||
"nav.hfss.help": "Alt+kéo chuột trái để trượt, Shift+Alt+chuột trái để thu phóng, Ctrl+kéo chuột trái từ vùng trống để xoay",
|
||||
"nav.inventor.help": "Kéo chuột giữa để trượt, Shift + chuột giữa để xoay, Ctrl + chuột giữa để thu phóng, kéo chuột phải để xoay",
|
||||
"nav.maya.help": "Alt+kéo chuột trái để xoay, Alt+chuột giữa để trượt, Alt+chuột phải để thu phóng; kéo chuột giữa cũng trượt",
|
||||
"nav.nx.help": "Kéo chuột giữa để xoay, Shift+chuột giữa để kéo ngang (NX: giữa + phải), Ctrl+chuột giữa để thu phóng (NX: giữa + trái); kéo chuột phải không di chuyển camera",
|
||||
"nav.openscad.help": "Kéo chuột trái trên vùng trống để xoay, Shift + chuột trái để quét chọn vùng, kéo hình học phác thảo để chỉnh sửa; kéo chuột phải hoặc chuột giữa để trượt, Shift + kéo chuột phải hoặc chuột giữa để thu phóng",
|
||||
"nav.perspective.sketch": "Chế độ chỉnh sửa phác thảo sử dụng góc nhìn trực giao. Hãy hoàn tất phác thảo để chuyển sang góc nhìn phối cảnh.",
|
||||
"nav.right_drag_orbits.help": "Tắt: kéo chuột phải không di chuyển camera, và nút phải chỉ mở menu ngữ cảnh. Chọn kiểu chuột SolidWorks sẽ tắt tùy chọn này.",
|
||||
@@ -1744,6 +2031,11 @@
|
||||
"not a move": "không phải một phép di chuyển",
|
||||
"not a number": "không phải là số",
|
||||
"open a sketch first": "hãy mở một phác thảo trước",
|
||||
"parameters.apply_live": "Áp dụng mỗi thay đổi khi rời khỏi ô của nó",
|
||||
"parameters.apply_live_tip": "Tắt: các thay đổi chờ đến khi nhấn Áp dụng hoặc OK, rồi thiết kế được dựng lại một lần cho tất cả. Hủy hoặc Escape sẽ bỏ chúng.",
|
||||
"parameters.held": "{count} thay đổi đang chờ Áp dụng",
|
||||
"parameters.held_hint": "Sửa biểu thức và đơn vị. Thay đổi chờ đến khi nhấn Áp dụng hoặc OK.",
|
||||
"parameters.held_one": "1 thay đổi đang chờ Áp dụng",
|
||||
"parts.automatic_name": "tự động",
|
||||
"parts.dimension.across_flats": "Cỡ cờ lê",
|
||||
"parts.dimension.bore": "Đường kính lỗ",
|
||||
@@ -1766,6 +2058,8 @@
|
||||
"parts.family.set_screw": "Vít trí lục giác chìm, đầu bằng",
|
||||
"parts.family.socket_head_cap_screw": "Bu lông lục giác chìm đầu trụ",
|
||||
"parts.family.washer": "Vòng đệm phẳng",
|
||||
"parts.holes": "Lỗ (tùy chọn)",
|
||||
"parts.placement_hint": "chọn một hoặc nhiều lỗ để lắp một chi tiết vào mỗi lỗ, hoặc nhấn OK để đặt tại gốc tọa độ",
|
||||
"pattern.alignment_2": "Căn chỉnh 2",
|
||||
"pattern.alignment_hint": "Số lượng bao gồm cả bản gốc. Căn giữa sẽ cân bằng các bản sao; Đổi hướng sẽ chọn phía bổ sung cho tổng số chẵn.",
|
||||
"pattern.direction_1": "Hướng 1",
|
||||
@@ -1818,6 +2112,8 @@
|
||||
"prefs.bottom_centre": "Giữa phía dưới",
|
||||
"prefs.bottom_right": "Góc dưới bên phải",
|
||||
"prefs.browser": "Cây thư mục",
|
||||
"prefs.browser_eye_left": "Biểu tượng mắt cạnh mũi tên thu gọn",
|
||||
"prefs.browser_eye_left_note": "Các hàng trong cây thư mục hiển thị biểu tượng mắt bật/tắt cạnh mũi tên thu gọn như trước đây, thay vì trong một cột ở đầu bên phải của các hàng.",
|
||||
"prefs.browser_reveal_on_hover": "Hiện khi di chuột",
|
||||
"prefs.browser_show_note": "Hiển thị giữ trình duyệt trên màn hình. Hiện khi di chuột ẩn nó cho đến khi con trỏ đến vị trí của nó hoặc thẻ mảnh ở cạnh trái, và nó vẫn mở khi con trỏ ở bên trong hoặc một menu của nó đang mở.",
|
||||
"prefs.browser_shown": "Hiển thị",
|
||||
@@ -1837,6 +2133,8 @@
|
||||
"prefs.ctrl_cmd": "Ctrl / Cmd",
|
||||
"prefs.curved_surfaces": "Các mặt cong",
|
||||
"prefs.curves": "Các đường cong",
|
||||
"prefs.dark_parts_shading": "Giữ hình dạng của chi tiết tối",
|
||||
"prefs.dark_parts_shading_help": "Tô bóng khung nhìn bằng ánh sáng tuyến tính với ánh sáng bầu trời dịu, để các mặt tối giữ được dải chuyển màu thay vì thành màu đen",
|
||||
"prefs.dead_zone_note": "Dải sọc chéo là vùng chết: các chuyển động bên trong vùng này sẽ bị bỏ qua.",
|
||||
"prefs.default": "mặc định",
|
||||
"prefs.design": "Mặc định thiết kế",
|
||||
@@ -1851,6 +2149,8 @@
|
||||
"prefs.edges": "Cạnh và đổ bóng",
|
||||
"prefs.extend": "Kéo dài",
|
||||
"prefs.extra_navigation": "Ctrl + kéo chuột trái trên vùng trống để xoay; giữ phím Cách (Space) để trượt góc nhìn.",
|
||||
"prefs.extrude_view_isometric": "Xoay sang góc nhìn trục đo khi mở Đùn khối",
|
||||
"prefs.extrude_view_return": "Trở lại góc nhìn trước khi đóng Đùn khối",
|
||||
"prefs.follows_os": "Theo hệ điều hành",
|
||||
"prefs.font": "Phông chữ",
|
||||
"prefs.font_fallback": "Các ký tự mà phông chữ đã chọn thiếu sẽ tự động dùng phông mặc định tích hợp, tránh tình trạng hiển thị ô vuông lỗi.",
|
||||
@@ -1866,8 +2166,11 @@
|
||||
"prefs.graphics_card_auto": "Tự động",
|
||||
"prefs.graphics_card_missing": "Card đồ họa đã lưu không khả dụng; chế độ Tự động đang được sử dụng.",
|
||||
"prefs.graphics_card_restart": "Có hiệu lực sau khi khởi động lại SolidCraft. Biến môi trường WGPU_ADAPTER_NAME sẽ ghi đè lựa chọn này.",
|
||||
"prefs.graphics_card_unused": "Card đồ họa đã lưu không được dùng cho cửa sổ này; card đang dùng hiện trong Trợ giúp › Giới thiệu và trên dòng trạng thái. Thử Tự động, hoặc đặt WGPU_ADAPTER_NAME thành phần tên card mang tính duy nhất.",
|
||||
"prefs.graphics_note": "Cân đối giữa tốc độ và độ mượt mà. Mỗi tùy chọn đều hiển thị hiệu ứng trực quan trên mẫu thử.",
|
||||
"prefs.graphics_presets_note": "Các cấu hình định sẵn sẽ thiết lập đồng thời các tùy chọn bên dưới.",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out": "Ẩn biểu tượng ràng buộc khi thu nhỏ",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out_note": "Biểu tượng ràng buộc biến mất khi bản phác được thu nhỏ đủ xa để không làm rối khung nhìn. Tắt: chúng giữ kích thước màn hình cố định ở mọi mức thu phóng.",
|
||||
"prefs.history": "Lịch sử",
|
||||
"prefs.history_origin_bodies": "Hiển thị gốc tọa độ và thân khối ở trên cùng",
|
||||
"prefs.history_origin_bodies_note": "Cây Lịch sử ở bên trái hoặc dưới cây thư mục sẽ bắt đầu với thư mục Thân khối và Gốc tọa độ của cụm chi tiết đang kích hoạt, cùng biểu tượng mắt bật/tắt và trình đơn tương tự như trong cây thư mục. Dòng Lịch sử ở cạnh dưới không thay đổi.",
|
||||
@@ -1878,6 +2181,8 @@
|
||||
"prefs.history_sketches_note": "Khi tùy chọn Phác thảo được đặt thành Dưới tính năng tương ứng, cây Lịch sử ở bên trái sẽ liệt kê mỗi phác thảo thụt vào một cấp dưới tính năng đầu tiên được tạo từ nó (khi khung đủ rộng để hiển thị tên). Dòng thời gian ở cạnh dưới luôn giữ nguyên thứ tự tạo.",
|
||||
"prefs.history_sketches_under_feature": "Dưới tính năng tương ứng",
|
||||
"prefs.hold_stop_snapping": "Giữ để tạm dừng bắt dính",
|
||||
"prefs.home_fit_size": "Cỡ Home và Khớp",
|
||||
"prefs.home_fit_size_note": "Mô hình chiếm bao nhiêu phần khung nhìn khi Home, Khớp, một thiết kế vừa mở hoặc đổi góc nhìn bằng khối điều hướng đưa nó vào khung hình, dù tùy chọn bên dưới bật hay tắt. 100 %: lấp đầy khung nhìn giữa các bảng, la bàn và thanh điều hướng.",
|
||||
"prefs.icons_only": "Chỉ hiện biểu tượng",
|
||||
"prefs.imported_file": "Tệp đã nhập",
|
||||
"prefs.in_browser": "Trong cây thư mục",
|
||||
@@ -1886,13 +2191,20 @@
|
||||
"prefs.interface_language": "Ngôn ngữ giao diện",
|
||||
"prefs.interface_note": "Diện mạo của SolidCraft và cách bố trí các bảng điều khiển.",
|
||||
"prefs.interval_minutes": "{n} phút",
|
||||
"prefs.invert_navigator_arrows": "Đảo ngược mũi tên xoay của khối điều hướng",
|
||||
"prefs.invert_navigator_arrows_note": "Các mũi tên quanh khối xoay camera theo hướng mũi tên chỉ, như trong Fusion và Inventor: mũi tên bên trái chỉ sang phải và đưa camera sang phải. Khi tắt: mũi tên xoay khối về phía cạnh chứa nó, nên mũi tên bên trái đưa camera sang trái. Hai mũi tên cuộn cong không bị ảnh hưởng.",
|
||||
"prefs.keep_work_on_tab_switch": "Giữ hộp thoại và công cụ mở khi chuyển giữa các thiết kế",
|
||||
"prefs.keep_work_on_tab_switch_note": "Mỗi thẻ thiết kế giữ hộp thoại hoặc công cụ đang mở, cùng những gì bạn đã chọn và nhập trong đó, và thẻ thanh công cụ của nó. Chúng vẫn còn đó khi bạn quay lại thiết kế. Tắt: chuyển thiết kế sẽ hủy chúng và hiển thị thẻ Mô hình.",
|
||||
"prefs.labels": "Nhãn chữ",
|
||||
"prefs.language_system": "Hệ thống",
|
||||
"prefs.layout": "Bố cục",
|
||||
"prefs.layout_note": "Chế độ Gọn (Compact) gắn các bảng vào mép cửa sổ. Độ trong suốt của Cây thư mục chỉ khả dụng ở chế độ Nổi (Floating). Thay đổi vị trí của Trợ lý trong trang Trợ lý.",
|
||||
"prefs.left": "Bên trái",
|
||||
"prefs.left_click": "Nhấp chuột trái",
|
||||
"prefs.line_drag_draws_one": "Nhấn và kéo vẽ một đường",
|
||||
"prefs.line_drag_draws_one_note": "Trong công cụ Đường, nhấn, kéo rồi thả sẽ vẽ một đường từ điểm nhấn đến điểm thả, và kết thúc ở đó. Nhấp vẫn vẽ một chuỗi. Tắt: kéo đặt một điểm tại nơi thả, như một lần nhấp.",
|
||||
"prefs.line_hover_tangent_arc": "Dừng trên điểm cuối của đường để chuyển sang cung tiếp tuyến",
|
||||
"prefs.line_hover_tangent_arc_note": "Trong công cụ Đường, sau khi vẽ một đoạn, hãy rời điểm cuối của chuỗi, quay lại và giữ yên con trỏ trên đó: lần nhấp tiếp theo sẽ kết thúc một cung tiếp tuyến, và cùng thao tác đó sẽ quay lại đường thẳng. Tắt: dừng ở đó không có tác dụng.",
|
||||
"prefs.linked_designs": "Thiết kế liên kết",
|
||||
"prefs.live_input": "Nhập liệu trực tiếp",
|
||||
"prefs.live_preview": "Xem trước trực tiếp",
|
||||
@@ -1906,6 +2218,9 @@
|
||||
"prefs.max_file_size_step": "Tệp STEP và tệp nhập",
|
||||
"prefs.max_file_size_web": "Ứng dụng web mở tệp STEP và tệp nhập tối đa 512 MB, thiết kế tối đa 256 MB: thẻ trình duyệt không chứa được tệp lớn hơn. Ứng dụng máy tính cho phép tăng các giới hạn này.",
|
||||
"prefs.megabytes": "MB",
|
||||
"prefs.menu_grid": "Biểu tượng lớn",
|
||||
"prefs.menu_list": "Danh sách",
|
||||
"prefs.menus": "Menu",
|
||||
"prefs.minutes": "phút",
|
||||
"prefs.minutes_suffix": " phút",
|
||||
"prefs.mouse": "Chuột và bàn di cảm ứng",
|
||||
@@ -1913,6 +2228,8 @@
|
||||
"prefs.mouse_mapping": "Gán chức năng chuột",
|
||||
"prefs.navigation": "Điều hướng góc nhìn",
|
||||
"prefs.navigation_note": "Cách chuột, bàn di cảm ứng và chuột 3D di chuyển góc nhìn.",
|
||||
"prefs.navigator_fit": "Khớp mô hình sau khi đổi góc nhìn bằng khối điều hướng",
|
||||
"prefs.navigator_fit_note": "Nhấp vào một mặt, góc hoặc mũi tên của khối lập phương, hoặc một trục của gizmo, cũng nhìn vào tâm mô hình từ một khoảng cách duy nhất chứa trọn nó từ mọi phía (khối cầu bao). Khi bật, góc nhìn chuẩn (Home) dùng cùng mức thu phóng và tâm đó, nên các góc nhìn chọn sau chỉ xoay. Tắt: góc nhìn xoay tại chỗ, giữ nguyên điểm nhìn và mức thu phóng.",
|
||||
"prefs.network_host_remove": "Xóa",
|
||||
"prefs.network_locations": "Cho phép các vị trí mạng trong thiết kế",
|
||||
"prefs.network_locations_note": "Khi tắt: các tệp liên kết của thiết kế trên máy tính khác (\\\\server\\share) chỉ được mở từ các máy chủ được liệt kê tại đây, hoặc sau khi bạn đồng ý khi được hỏi.",
|
||||
@@ -1925,10 +2242,16 @@
|
||||
"prefs.origin_plane_names": "Tên các mặt phẳng gốc",
|
||||
"prefs.origin_plane_names_note": "Tên hiển thị trong trình duyệt, hộp thoại và danh sách. {top} là XY, {front} là XZ và {right} là YZ, với Z hướng lên. Lệnh, script và thiết kế đã lưu vẫn dùng XY, XZ và YZ.",
|
||||
"prefs.overall_speed": "Tốc độ tổng thể",
|
||||
"prefs.parameter_list_rows": "Số dòng danh sách tham số",
|
||||
"prefs.parameter_list_rows_tip": "Phím mũi tên xuống trong ô giá trị trống liệt kê các tham số, mục yêu thích trước, tối đa số này. Ít hơn giúp danh sách nhẹ trong thiết kế lớn.",
|
||||
"prefs.persistent_ribbon_pressed": "Tô sáng lệnh đang bật trên dải băng",
|
||||
"prefs.persistent_ribbon_pressed_help": "Tô sáng các lệnh trên dải băng khi hiệu ứng của chúng đang bật. Tắt tùy chọn này để giữ giao diện trung tính và trợ giúp lệnh như trước.",
|
||||
"prefs.perspective_fov": "Trường nhìn",
|
||||
"prefs.placement": "Vị trí đặt",
|
||||
"prefs.prefer_free_sketch_points": "Ưu tiên điểm phác thảo có thể di chuyển khi các điểm chồng lên nhau",
|
||||
"prefs.preview_choices": "Xem trước các lựa chọn của bạn",
|
||||
"prefs.print_face_highlight": "Tô sáng mặt in",
|
||||
"prefs.print_face_highlight_tip": "Mức tô màu và viền mặt in của thân trong khung nhìn. 0 % không tô sáng.",
|
||||
"prefs.profile_active": "Hồ sơ đang dùng",
|
||||
"prefs.profile_applied": "Đã áp dụng hồ sơ.",
|
||||
"prefs.profile_changed": "Cài đặt đã thay đổi kể từ khi lưu hồ sơ. “Lưu” sẽ ghi chúng vào hồ sơ.",
|
||||
@@ -1950,9 +2273,13 @@
|
||||
"prefs.quality_fastest": "nhanh nhất",
|
||||
"prefs.quality_slowest": "chậm nhất (chất lượng cao nhất)",
|
||||
"prefs.quality_smoother": "mượt mà hơn",
|
||||
"prefs.quick_measure": "Đo nhanh ở góc khung nhìn",
|
||||
"prefs.quick_measure_note": "Hiển thị kích thước của đối tượng được chọn ở góc dưới bên phải khung nhìn, phía trên Lịch sử: chiều dài của cạnh (hoặc Ø và R với cạnh tròn), diện tích của mặt, vị trí của điểm, khoảng cách và góc giữa hai đối tượng, tổng của nhiều cạnh hoặc mặt. Nhấp để sao chép.",
|
||||
"prefs.render_previous_geometry_budget": "Dùng ngân sách hình học trước đây cho bản xem trước kết xuất",
|
||||
"prefs.render_previous_geometry_budget_help": "Khôi phục giới hạn hình học cố định trước đây (512 MiB trên máy tính 64 bit, 128 MiB trên các nền tảng khác) thay cho ngân sách dựa trên thiết bị.",
|
||||
"prefs.reports_saved": "Đã lưu {n}",
|
||||
"prefs.ribbon_click_ends_tool": "Nhấp vào nút của công cụ đang chạy sẽ kết thúc nó",
|
||||
"prefs.ribbon_click_ends_tool_note": "Nhấp vào nút ruy-băng đang sáng của công cụ phác thảo đang dùng sẽ kết thúc công cụ, để các cú nhấp trong khung nhìn lại chọn đối tượng. Tắt: cú nhấp khởi động lại công cụ.",
|
||||
"prefs.ribbon_reveal": "Hiện kết quả tìm kiếm trên ribbon",
|
||||
"prefs.ribbon_reveal_note": "Khi rê chuột lên một kết quả trong Tìm lệnh, ribbon cho biết lệnh nằm ở đâu: tab, nút hoặc dòng của nó trong menu thả xuống của một bảng. Lệnh bắt đầu từ tìm kiếm sẽ nhấp nháy ở đó, và lệnh đang chạy từ menu thả xuống sẽ đánh dấu bảng của nó.",
|
||||
"prefs.right_click": "Nhấp chuột phải",
|
||||
@@ -1963,6 +2290,8 @@
|
||||
"prefs.search_empty": "Không có cài đặt nào khớp",
|
||||
"prefs.select": "Chọn",
|
||||
"prefs.select_one_item": "Chọn một mục",
|
||||
"prefs.select_other_hidden": "Chọn hình học ẩn bằng Chọn đối tượng khác",
|
||||
"prefs.select_other_hidden_help": "Bật: bao gồm các khối, bản phác thảo ẩn và cạnh bị che gần con trỏ. Tắt: dùng danh sách ban đầu chỉ gồm hình học đang hiển thị ngay dưới con trỏ.",
|
||||
"prefs.selecting": "Đang chọn",
|
||||
"prefs.shift": "Shift",
|
||||
"prefs.shift_add_ctrl_toggle": "Shift chỉ thêm; Ctrl / Cmd đảo trạng thái chọn",
|
||||
@@ -1974,11 +2303,18 @@
|
||||
"prefs.sketch_align_points_note": "Khi vẽ, một điểm được căn ngang theo một điểm phác thảo và căn dọc theo điểm khác cùng lúc, kèm đường dẫn chấm; cú nhấp giữ cả hai ràng buộc căn. Tắt: chỉ căn theo điểm trước, mỗi lần một trục.",
|
||||
"prefs.sketch_conflict_colour": "Hình học xung đột theo màu xung đột",
|
||||
"prefs.sketch_conflict_colour_note": "Khi các ràng buộc của bản phác xung đột, các đường cong và điểm mà một ràng buộc lỗi giữ cũng được vẽ bằng màu xung đột, không chỉ ký hiệu hay kích thước của nó. Tắt: chúng giữ màu thường.",
|
||||
"prefs.sketch_construction_lines": "Công cụ đường dựng hình mở rộng",
|
||||
"prefs.sketch_exit_view": "Khi kết thúc phác thảo",
|
||||
"prefs.sketch_exit_view.keep": "Giữ góc nhìn hiện tại",
|
||||
"prefs.sketch_exit_view.previous": "Trở về góc nhìn trước đó",
|
||||
"prefs.sketch_exit_view.unless_rotated": "Trở về góc nhìn trước trừ khi đã xoay",
|
||||
"prefs.sketch_exit_view_note": "Góc nhìn sẽ chuyển đến đâu sau khi bấm Hoàn tất phác thảo, Hủy bỏ hoặc bấm phím Esc hai lần.",
|
||||
"prefs.sketch_face_activates_part": "Phác thảo trên mặt của một chi tiết sẽ kích hoạt chi tiết đó",
|
||||
"prefs.sketch_face_activates_part_note": "Bản phác thảo bắt đầu trên mặt của một khối thuộc thành phần khác sẽ kích hoạt thành phần đó trước, nên bản phác thảo thuộc về nó và nằm cùng chi tiết đó trong trình duyệt. Chi tiết vẫn được kích hoạt sau đó. Tắt: bản phác thảo thuộc thành phần đang hoạt động.",
|
||||
"prefs.sketch_open_look_at": "Xoay góc nhìn trực diện phác thảo khi mở",
|
||||
"prefs.sketch_open_look_at_note": "Tắt: tạo hoặc chỉnh sửa phác thảo sẽ giữ nguyên góc nhìn. Dùng Nhìn trực diện để nhìn thẳng vào phác thảo khi cần.",
|
||||
"prefs.sketch_recent_snap": "Tự động bắt điểm vào tâm và trung điểm gần đây",
|
||||
"prefs.sketch_recent_snap_note": "Khi vẽ, con trỏ được bắt vào nơi các đường dẫn của hai tâm đường tròn hoặc trung điểm cạnh thẳng gần nhất cắt nhau. Tắt: các đường dẫn chỉ để xem và con trỏ không di chuyển.",
|
||||
"prefs.sketch_selection": "Phác thảo & chọn đối tượng",
|
||||
"prefs.sketch_selection_heading": "Phác thảo và lựa chọn",
|
||||
"prefs.sketch_selection_note": "Cách phác thảo bắt dính và cách nhấp chuột chọn đối tượng.",
|
||||
@@ -1988,6 +2324,8 @@
|
||||
"prefs.sketch_tab_always_note": "Thẻ Bản phác vẫn nằm trên thanh công cụ, ngay sau Mô hình, khi không có bản phác nào đang mở. Khi đó các công cụ vẽ của nó bắt đầu một bản phác trên mặt phẳng hoặc mặt đã chọn, hoặc trên mặt phẳng bạn chọn tiếp theo, với công cụ sẵn sàng trong đó.",
|
||||
"prefs.sketch_tracking_guides": "Đường căn chỉnh tâm và trung điểm",
|
||||
"prefs.sketch_tracking_guides_note": "Di con trỏ lên tâm đường tròn hoặc trung điểm của cạnh thẳng, rồi di chuyển theo phương ngang hoặc dọc để hiển thị đường căn chỉnh nét đứt tạm thời.",
|
||||
"prefs.sketch_tracking_points": "Đường căn chỉnh từ điểm đầu mút và góc khi vẽ",
|
||||
"prefs.sketch_tracking_points_note": "Khi một công cụ vẽ đang chờ một điểm, di con trỏ lên đầu mút của đường thẳng hoặc cung, góc của hình chữ nhật hoặc một điểm tự do sẽ hiển thị đường căn chỉnh nét đứt tạm thời giống như ở tâm hoặc trung điểm. Tắt: chỉ tâm và trung điểm.",
|
||||
"prefs.sketching": "Vẽ phác thảo",
|
||||
"prefs.snap_drawing_note": "Khi đang vẽ hoặc kéo một điểm phác thảo.",
|
||||
"prefs.source": "Nguồn",
|
||||
@@ -2004,6 +2342,24 @@
|
||||
"prefs.status_error": "Lỗi",
|
||||
"prefs.status_selected": "Đã chọn",
|
||||
"prefs.status_warning": "Cảnh báo",
|
||||
"prefs.structure.appearance": "Giao diện",
|
||||
"prefs.structure.appearance_note": "Màu sắc, văn bản và khả năng tiếp cận.",
|
||||
"prefs.structure.in_profile": "Trong hồ sơ",
|
||||
"prefs.structure.layout": "Bố cục",
|
||||
"prefs.structure.layout_note": "Vị trí các phần của cửa sổ.",
|
||||
"prefs.structure.look": "Hiển thị",
|
||||
"prefs.structure.measure_pointer": "Đo lường và con trỏ",
|
||||
"prefs.structure.mouse3d": "Chuột 3D",
|
||||
"prefs.structure.mouse3d_note": "SpaceMouse và SpaceNavigator.",
|
||||
"prefs.structure.navigation_note": "Chuột và bàn di chuột. Chuột 3D có trang riêng.",
|
||||
"prefs.structure.profile": "Hồ sơ",
|
||||
"prefs.structure.profile_edited": "Đã thay đổi kể từ lần lưu",
|
||||
"prefs.structure.profile_hover": "Được lưu trong hồ sơ cài đặt",
|
||||
"prefs.structure.scale_percent": "{percent}%",
|
||||
"prefs.structure.sketch": "Phác thảo",
|
||||
"prefs.structure.tools": "Công cụ",
|
||||
"prefs.structure.tools_note": "Cách các công cụ dựng mô hình hoạt động.",
|
||||
"prefs.structure.work": "Công việc",
|
||||
"prefs.supersampling_brief": "Vẽ khung nhìn ở độ phân giải lớn hơn rồi lọc giảm tỷ lệ: rất sắc nét, nhưng tốn tài nguyên hơn.",
|
||||
"prefs.tab_accent_note": "Màu nhấn theo tab đang kích hoạt",
|
||||
"prefs.theme_file": "tệp chủ đề",
|
||||
@@ -2015,6 +2371,16 @@
|
||||
"prefs.theme_follow_off": "Tắt",
|
||||
"prefs.theme_follow_stop": "Dừng theo dõi",
|
||||
"prefs.theme_import_hint": "Nhấp để chọn tệp giao diện, thả tệp vào đây, hoặc nhấn Ctrl+V (Cmd+V trên Mac) khi đã sao chép một giao diện",
|
||||
"prefs.theme_option_opacity": "Độ đục",
|
||||
"prefs.theme_option_opacity_help": "Điều chỉnh độ đục của các bảng nổi. Giới hạn độ đục tối thiểu giúp văn bản luôn dễ đọc trên nền màu của khung nhìn.",
|
||||
"prefs.theme_option_tab_colours": "Màu thẻ",
|
||||
"prefs.theme_option_tab_colours_help": "Sử dụng màu bảng điều khiển và khung nhìn của chủ đề này cho từng thẻ trên dải băng.",
|
||||
"prefs.theme_option_tab_fade_ms": "Chuyển đổi thẻ",
|
||||
"prefs.theme_option_tab_fade_ms_help": "Chuyển dần màu của bảng điều khiển và khung nhìn khi đổi thẻ. Đặt thành 0 để chuyển ngay lập tức.",
|
||||
"prefs.theme_options_badge": "Tùy chọn",
|
||||
"prefs.theme_options_more": "Thêm · {count}",
|
||||
"prefs.theme_options_reset": "Đặt lại",
|
||||
"prefs.theme_options_unavailable": "Không khả dụng trên thiết bị này",
|
||||
"prefs.theme_paste": "Dán giao diện",
|
||||
"prefs.theme_paste_none": "Bộ nhớ tạm không chứa giao diện SolidCraft nào",
|
||||
"prefs.timeline_half_hour": "−30 phút",
|
||||
@@ -2036,13 +2402,23 @@
|
||||
"prefs.under_cursor": "Dưới con trỏ chuột",
|
||||
"prefs.units_precision": "Đơn vị và độ chính xác",
|
||||
"prefs.updates": "Cập nhật ứng dụng",
|
||||
"prefs.value_boxes_in_view": "Hiện giá trị cạnh tay nắm trong khung nhìn",
|
||||
"prefs.value_boxes_in_view_tip": "Giá trị của lệnh (Khoảng cách, Bán kính…) trong một ô cạnh tay nắm, phía trên mô hình. Tắt: bạn nhập giá trị trong cửa sổ lệnh, cửa sổ này nhận bàn phím sau khi chọn, và không có gì che mô hình.",
|
||||
"prefs.view": "Hành vi góc nhìn",
|
||||
"prefs.view_confirm_corner": "Nút Đồng ý và Hủy bỏ ở góc khung nhìn",
|
||||
"prefs.view_confirm_corner_note": "Khi hộp thoại hoặc môi trường phác thảo đang mở, dấu tích và dấu chéo ở góc trên bên phải khung nhìn có chức năng tương tự nút Đồng ý và Hủy bỏ của hộp thoại, hoặc để hoàn tất và hủy phác thảo. Khối điều hướng góc nhìn sẽ dời xuống bên dưới chúng.",
|
||||
"prefs.viewport": "Khung nhìn 3D",
|
||||
"prefs.viewport_analysis_status": "Hiện trạng thái phân tích trong khung nhìn",
|
||||
"prefs.viewport_analysis_status_help": "Hiện các phân tích đang bật phía trên khung nhìn và mở chú giải từ từng mục. Esc tắt phân tích mới nhất. Tắt tùy chọn để khôi phục chú giải ở góc và hành vi Esc trước đây.",
|
||||
"prefs.viewport_background": "Nền",
|
||||
"prefs.viewport_background_colour": "Màu",
|
||||
"prefs.viewport_background_theme": "Dải màu của chủ đề",
|
||||
"prefs.viewport_section_status": "Hiện trạng thái mặt cắt trong khung nhìn",
|
||||
"prefs.viewport_section_status_help": "Hiện thiết lập mặt cắt trong khung nhìn. Escape và nút dải công cụ đang bật sẽ tắt mặt cắt. Tắt tùy chọn để giữ cách điều khiển mặt cắt trước đây.",
|
||||
"prefs.viewport_status_details": "Chi tiết trực tiếp trong khung nhìn",
|
||||
"prefs.viewport_status_details_help": "Chỉnh sửa thiết lập phân tích và mặt cắt đang hoạt động trong các thẻ chi tiết chuẩn. Tắt để khôi phục chú giải phân tích chỉ đọc và hộp thoại Mặt cắt.",
|
||||
"prefs.viewport_status_summary": "Tóm tắt các mục trạng thái khung nhìn",
|
||||
"prefs.viewport_status_summary_help": "Gộp từ ba mục trạng thái khung nhìn trở lên thành một huy hiệu tóm tắt. Tắt để giữ mọi mục trong hàng đầy đủ.",
|
||||
"prefs.wheel": "Con lăn chuột",
|
||||
"prefs.wheel_trackpad": "Con lăn chuột và bàn di cảm ứng",
|
||||
"prefs.workspace": "Không gian làm việc",
|
||||
@@ -2052,6 +2428,10 @@
|
||||
"properties.title": "Thuộc tính: {name}",
|
||||
"recovery.days_ago": "{count} ngày trước",
|
||||
"recovery.detail": "{file} · {features} tính năng · tự động lưu {when}",
|
||||
"recovery.discard_all": "Hủy bỏ tất cả",
|
||||
"recovery.discard_all_detail": "Không thể hoàn tác thao tác này.",
|
||||
"recovery.discard_all_title": "Hủy bỏ {count} bản tự động lưu?",
|
||||
"recovery.discard_all_title_one": "Hủy bỏ 1 bản tự động lưu?",
|
||||
"recovery.hours_ago": "{count} giờ trước",
|
||||
"recovery.just_now": "vừa xong",
|
||||
"recovery.min_ago": "{count} phút trước",
|
||||
@@ -2917,7 +3297,9 @@
|
||||
"render.output_ready": "Sẵn sàng kết xuất",
|
||||
"render.output_run_check": "Chạy kiểm tra",
|
||||
"render.output_size_limit": "{method}: tối đa {dimension} px mỗi cạnh và {pixels} điểm ảnh. Kích thước lớn nhất vừa khít: {width} × {height}.",
|
||||
"render.output_size_method_profile": "Để kết xuất {width} × {height}, hãy chọn {method} với cấu hình tài nguyên CPU {profile} hoặc một kích thước nhỏ hơn.",
|
||||
"render.output_size_ok": "Kích thước ổn · {width} × {height} px",
|
||||
"render.output_size_profile": "Để kết xuất {width} × {height}, hãy chọn cấu hình tài nguyên CPU {profile} hoặc một kích thước nhỏ hơn.",
|
||||
"render.output_swap_orientation": "Hoán đổi chiều rộng và chiều cao",
|
||||
"render.output_tools_inspector": "Chỉnh kích thước và định dạng trong bảng thuộc tính Đầu ra.",
|
||||
"render.output_view_image": "Xem ảnh",
|
||||
@@ -3130,6 +3512,7 @@
|
||||
"render.size_custom": "Tùy chỉnh…",
|
||||
"render.size_full_hd": "Full HD",
|
||||
"render.size_hd": "HD",
|
||||
"render.size_needs_profile": "{size} · cần {profile}",
|
||||
"render.size_presets": "Cỡ đặt sẵn",
|
||||
"render.size_presets_pending": "Sẽ có cùng trình chỉnh Đầu ra",
|
||||
"render.size_preview": "Xem trước",
|
||||
@@ -3417,6 +3800,24 @@
|
||||
"sheet.flange_type_contour": "Đường viền",
|
||||
"sheet.flange_type_edge": "Cạnh",
|
||||
"sheet.no_body": "chưa có khối tấm kim loại: hãy bắt đầu bằng Cánh gập > Cơ sở (Base), hoặc chuyển một tấm phẳng thành tấm kim loại bằng lệnh 'Chuyển thành tấm kim loại' (chọn mặt phẳng lớn của nó)",
|
||||
"sheet.personal_rules.confirm_delete": "Xác nhận xóa",
|
||||
"sheet.personal_rules.delete": "Xóa",
|
||||
"sheet.personal_rules.delete_prompt": "Xóa quy tắc cá nhân này? Các quy tắc đã có trong thiết kế sẽ không thay đổi.",
|
||||
"sheet.personal_rules.full": "Thư viện cá nhân đã chứa tối đa 64 quy tắc.",
|
||||
"sheet.personal_rules.invalid_name": "Nhập một tên ngắn gọn, không chứa ký tự xuống dòng hoặc ký tự điều khiển.",
|
||||
"sheet.personal_rules.invalid_values": "Hãy điền đủ các giá trị của quy tắc: mỗi giá trị phải tính được trong thiết kế này, với độ dày dương và hệ số K từ 0 đến 1.",
|
||||
"sheet.personal_rules.missing": "Quy tắc cá nhân đã chọn không còn khả dụng.",
|
||||
"sheet.personal_rules.name": "Tên quy tắc",
|
||||
"sheet.personal_rules.name_exists": "Quy tắc cá nhân với tên này đã tồn tại. Vui lòng sử dụng tên khác.",
|
||||
"sheet.personal_rules.name_hint": "Tên duy nhất",
|
||||
"sheet.personal_rules.overwrite": "Lưu các thay đổi vào quy tắc cá nhân đã chọn",
|
||||
"sheet.personal_rules.rename": "Đổi tên",
|
||||
"sheet.personal_rules.rule": "Quy tắc cá nhân",
|
||||
"sheet.personal_rules.save": "Lưu mới",
|
||||
"sheet.personal_rules.scope": "Được lưu trong hồ sơ cá nhân của bạn cho tất cả thiết kế.",
|
||||
"sheet.personal_rules.select": "Chọn một quy tắc",
|
||||
"sheet.personal_rules.title": "Quy tắc cá nhân",
|
||||
"sheet.personal_rules.unsupported": "Quy tắc này có các giá trị mà phiên bản hiện tại không thể sử dụng.",
|
||||
"shortcut.json_error": "tham số phải là JSON: {error}",
|
||||
"shortcut.no_command": "không có lệnh `{id}`; văn bản trước JSON phải là mã lệnh",
|
||||
"shortcut.pin": "Ghim lên đầu hộp S",
|
||||
@@ -3453,8 +3854,10 @@
|
||||
"sketch_text.align_right": "Phải",
|
||||
"sketch_text.bold": "In đậm",
|
||||
"sketch_text.builtin_font": "{family} (tích hợp sẵn)",
|
||||
"sketch_text.formula": "Bắt đầu bằng = để tạo chữ từ các tham số: ='W' + number(Width)",
|
||||
"sketch_text.italic": "In nghiêng",
|
||||
"sketch_text.loading_fonts": "Đang tìm kiếm các phông chữ đã cài đặt…",
|
||||
"sketch_text.no_bold": "Phông chữ tích hợp không có kiểu in đậm: chọn một phông chữ đã cài đặt",
|
||||
"sketch_text.on_path": "Văn bản đi theo đường dẫn: đường cong định vị văn bản",
|
||||
"sketch_text.path_clear": "Gỡ văn bản khỏi đường cong dẫn",
|
||||
"sketch_text.path_hint": "Đường cong phác thảo mà văn bản chạy theo: nhấp vào đây, sau đó chọn đường cong",
|
||||
@@ -3593,6 +3996,8 @@
|
||||
"ui.3d_mouse_section": "Chuột 3D",
|
||||
"ui.3d_mouse_show_in_view": "Hiện chuột 3D trong khung nhìn 3D",
|
||||
"ui.3d_mouse_show_in_view_tip": "Hình chuột 3D của bạn ở góc dưới bên trái, chuyển động theo bạn.",
|
||||
"ui.3d_mouse_sketch_orbit": "Xoay bản phác thảo bằng chuột 3D",
|
||||
"ui.3d_mouse_sketch_orbit_tip": "Chuột 3D cũng xoay khung nhìn khi bản phác thảo đang mở và được nhìn thẳng, như chuột thường. Tắt: chỉ di chuyển và thu phóng bản phác thảo cho đến khi bạn nghiêng khung nhìn.",
|
||||
"ui.3d_mouse_skip": "Thiết bị của tôi không làm được điều này",
|
||||
"ui.3d_mouse_skip_tip": "Bỏ qua chuyển động này theo cả hai chiều; việc hiệu chuẩn sẽ không dùng nó.",
|
||||
"ui.3d_mouse_speed": "Tốc độ chuột 3D",
|
||||
@@ -3621,6 +4026,8 @@
|
||||
"ui.3d_mouse_step_twist_counterclockwise": "Xoay núm điều khiển ngược chiều kim đồng hồ, giữ nguyên, rồi thả ra.",
|
||||
"ui.3d_mouse_switch_cap": "Hiệu chuẩn theo kiểu trở về giữa",
|
||||
"ui.3d_mouse_switch_trackball": "Hiệu chuẩn như bi xoay",
|
||||
"ui.3d_mouse_use_direct": "Dùng trình điều khiển trực tiếp",
|
||||
"ui.3d_mouse_use_direct_tip": "Đọc chuột 3D trực tiếp (hidraw) thay vì qua spacenavd.",
|
||||
"ui.3d_mouse_view_axis": "Trục khung nhìn",
|
||||
"ui.3d_mouse_view_off": "Tắt",
|
||||
"ui.3d_mouse_view_off_tip": "Hồ sơ của trình điều khiển chuột 3D tắt trục này, nên chuyển động của nó không làm khung nhìn di chuyển. Chọn chuyển động của trục khác ở đây sẽ hoán đổi hai trục, và chuyển động đó không còn di chuyển khung nhìn.",
|
||||
@@ -3659,6 +4066,7 @@
|
||||
"ui.agent_chat_auth_terminal": "Chạy lệnh này trong cửa sổ dòng lệnh, sau đó nhấp Kết nối lại:",
|
||||
"ui.agent_chat_auth_title": "Đăng nhập vào AI Agent",
|
||||
"ui.agent_chat_cancel": "Hủy bỏ",
|
||||
"ui.agent_chat_cannot_start": "Đã cài đặt nhưng không khởi động được: {error}",
|
||||
"ui.agent_chat_changes": "Thay đổi: {n}, trong 1 bước hoàn tác",
|
||||
"ui.agent_chat_changes_n": "{n} thay đổi",
|
||||
"ui.agent_chat_changes_of": "{n}/{limit} thay đổi",
|
||||
@@ -3751,9 +4159,12 @@
|
||||
"ui.agent_chat_queued_stopped": "Đã xếp hàng (đã dừng, chưa gửi)",
|
||||
"ui.agent_chat_refresh": "Làm mới",
|
||||
"ui.agent_chat_refused": "Không được phép đối với tác tử: {reason}",
|
||||
"ui.agent_chat_reinstall": "{agent} đã được cài đặt ({program}) nhưng không khởi động khi SolidCraft kiểm tra: {error}\nBản cài đặt có thể chưa hoàn tất, hoặc dành cho loại máy tính khác. Hãy cài lại bằng `{install}`, kiểm tra rằng nó in ra phiên bản trong terminal, rồi nhấn Làm mới.",
|
||||
"ui.agent_chat_remove": "Xóa khỏi hàng đợi",
|
||||
"ui.agent_chat_remove_file": "Bỏ tệp này khỏi tin nhắn",
|
||||
"ui.agent_chat_remove_imported": "Gỡ khỏi tin nhắn này; chi tiết vẫn nằm trong thiết kế (sử dụng Hoàn tác để xóa)",
|
||||
"ui.agent_chat_reply_cut_off": "Câu trả lời đã chạm giới hạn độ dài trước khi xong nên có thể chưa đầy đủ. Hãy yêu cầu AI Agent tiếp tục, hoặc trả lời ngắn hơn.",
|
||||
"ui.agent_chat_reply_declined": "Mô hình đã từ chối trả lời tin nhắn này.",
|
||||
"ui.agent_chat_retry": "Thử lại",
|
||||
"ui.agent_chat_right": "Phải (Hình chiếu cạnh)",
|
||||
"ui.agent_chat_save": "Lưu",
|
||||
@@ -3812,12 +4223,17 @@
|
||||
"ui.ai_copy_suffix": "sao chép",
|
||||
"ui.ai_custom_url": "URL tùy chỉnh",
|
||||
"ui.ai_default": "Mặc định",
|
||||
"ui.ai_edit": "Sửa",
|
||||
"ui.ai_edit_agent_title": "Sửa AI Agent",
|
||||
"ui.ai_edit_gone": "AI Agent này đã bị xóa nên không có gì để lưu.",
|
||||
"ui.ai_edit_tip": "Đổi tên, lệnh hoặc endpoint của AI Agent này. Khóa đã lưu vẫn được ẩn.",
|
||||
"ui.ai_http_busy": "điểm cuối đang bận hoặc vượt quá giới hạn; vui lòng thử lại sau",
|
||||
"ui.ai_http_key": "điểm cuối từ chối khóa API: hãy kiểm tra trong Tùy chọn cài đặt > AI",
|
||||
"ui.ai_http_not_found": "không tìm thấy điểm cuối hoặc mô hình: hãy kiểm tra URL cơ sở và tên mô hình",
|
||||
"ui.ai_http_too_large": "cuộc trò chuyện quá lớn đối với điểm cuối này; hãy bắt đầu cuộc trò chuyện mới",
|
||||
"ui.ai_key": "Khóa API",
|
||||
"ui.ai_key_hint": "tùy chọn; lưu trữ bảo mật trong chuỗi khóa hệ thống",
|
||||
"ui.ai_key_keep_hint": "để trống để giữ khóa đã lưu",
|
||||
"ui.ai_key_needs_https": "Khóa chỉ được gửi qua HTTPS, hoặc trực tiếp trên máy tính này.",
|
||||
"ui.ai_key_note": "Được lưu an toàn trong Keychain hệ thống, không lưu trong cài đặt của SolidCraft. Để trống nếu dùng máy chủ cục bộ.",
|
||||
"ui.ai_keychain_error": "Chuỗi khóa hệ thống từ chối: {error}",
|
||||
@@ -3844,11 +4260,15 @@
|
||||
"ui.ai_permissions": "Quyền hạn",
|
||||
"ui.ai_preset": "Mẫu cấu hình sẵn",
|
||||
"ui.ai_protocol": "Giao thức",
|
||||
"ui.ai_reasoning_effort": "Mức độ suy luận",
|
||||
"ui.ai_reasoning_effort_field_hint": "trống = mặc định của nhà cung cấp",
|
||||
"ui.ai_reasoning_effort_hint": "Tùy chọn. Được gửi tới điểm cuối dưới dạng `reasoning_effort`; các giá trị được chấp nhận khác nhau tùy nhà cung cấp (ví dụ: `low`, `high` hoặc `max`). Giá trị bạn đặt ở đây không bao giờ bị SolidCraft thay thế. Để trống để không gửi gì và giữ mặc định của nhà cung cấp.",
|
||||
"ui.ai_remove": "Xóa",
|
||||
"ui.ai_request_timed_out": "Mô hình phản hồi lâu hơn {seconds} giây. Bạn có thể tăng thời gian chờ yêu cầu cho điểm cuối này trong Tùy chọn › Trợ lý.",
|
||||
"ui.ai_request_timeout": "Thời gian chờ yêu cầu",
|
||||
"ui.ai_request_timeout_hint": "Thời gian tối đa cho một yêu cầu tới điểm cuối này, từ 30 giây đến 1 giờ. Hãy tăng giá trị này đối với mô hình cục bộ xử lý chậm.",
|
||||
"ui.ai_reset": "Đặt lại",
|
||||
"ui.ai_save": "Lưu",
|
||||
"ui.ai_settings": "AI cài đặt…",
|
||||
"ui.ai_show_features": "Hiển thị các tính năng AI",
|
||||
"ui.ai_show_features_note": "Trò chuyện với tác tử: bảng điều khiển nơi tác tử lập trình hoặc điểm cuối mô hình thao tác trên thiết kế đang mở. Tắt: ẩn nút AI, phím tắt, menu và bảng điều khiển, không tìm kiếm hay khởi chạy tác tử.",
|
||||
@@ -3937,6 +4357,7 @@
|
||||
"ui.circle": "Hình tròn",
|
||||
"ui.circular_pattern": "Mảng tròn quanh trục",
|
||||
"ui.clear": "Xóa",
|
||||
"ui.clear_print_face": "Xóa mặt in",
|
||||
"ui.clear_recent": "Xóa danh sách gần đây",
|
||||
"ui.clear_the_selection": "Hủy chọn",
|
||||
"ui.click_selects_whole_bodies": "Nhấp chuột chọn toàn bộ thân khối",
|
||||
@@ -3971,6 +4392,15 @@
|
||||
"ui.constant": "Hằng số",
|
||||
"ui.constraints_conflict": "Xung đột ràng buộc",
|
||||
"ui.construction": "Đường gióng dựng hình",
|
||||
"ui.construction.angle_hint": "Đường dựng hình: nhấp một điểm rồi nhập góc hoặc chọn hướng",
|
||||
"ui.construction.bisector_hint": "Phân giác: chọn hai đường thẳng giao nhau rồi chọn nghiệm mong muốn",
|
||||
"ui.construction.common_hint": "Tiếp tuyến chung: chọn hai đường tròn/cung rồi chọn nghiệm mong muốn",
|
||||
"ui.construction.contact_hint": "Tiếp tuyến: chọn đường tròn/cung hoặc spline/conic hở rồi chọn tiếp điểm (đường cong tự do: chỉ đầu mút)",
|
||||
"ui.construction.external_hint": "Tiếp tuyến: chọn đường tròn hoặc cung, điểm ngoài rồi chọn nghiệm mong muốn",
|
||||
"ui.construction.free_hint": "Đường dựng hình: nhấp hai điểm; nhấp chuột phải để bắt đầu lại",
|
||||
"ui.construction.point_hint": "Đường dựng hình: nhấp điểm đi qua",
|
||||
"ui.construction.reference_hint": "Đường dựng hình: chọn đường thẳng rồi chọn điểm; nhấp chuột phải để đổi tham chiếu",
|
||||
"ui.construction.ribbon_label": "Đường phụ",
|
||||
"ui.context_menu": "Menu ngữ cảnh",
|
||||
"ui.continuity_g0": "Nếp gập G0",
|
||||
"ui.continuity_g1": "G1 tiếp tuyến",
|
||||
@@ -3998,6 +4428,7 @@
|
||||
"ui.dark": "Tối",
|
||||
"ui.default_modelling_orientation": "Hướng mô hình hóa mặc định",
|
||||
"ui.delete": "Xóa",
|
||||
"ui.delete_select_first": "Hãy chọn trước những gì cần xóa: tính năng, khối, thành phần hoặc hình học phác thảo",
|
||||
"ui.depth": "Độ sâu",
|
||||
"ui.design": "Thiết kế",
|
||||
"ui.design_properties.author": "Tác giả",
|
||||
@@ -4012,6 +4443,40 @@
|
||||
"ui.design_properties.project": "Dự án",
|
||||
"ui.design_properties.revision": "Lần sửa đổi (Revision)",
|
||||
"ui.design_saved": "Đã lưu vào {path}",
|
||||
"ui.details_access_caption": "Các bề mặt cho biết dụng cụ có thể tiếp cận chúng từ hướng đã chọn hay không.",
|
||||
"ui.details_angle": "Góc",
|
||||
"ui.details_continuity_caption": "Chỉnh sửa đường nối đã chọn. Các đường nối khác giữ nguyên thiết lập riêng.",
|
||||
"ui.details_continuity_stale": "Hình học trước đó: chạy lại phân tích để chỉnh sửa đường nối này hoặc điều chỉnh khung nhìn vừa với nó.",
|
||||
"ui.details_copy_list": "Sao chép danh sách",
|
||||
"ui.details_curvature": "Dung sai độ cong",
|
||||
"ui.details_curvature_caption": "Các bề mặt được tô màu theo bán kính cong cục bộ.",
|
||||
"ui.details_direction": "Hướng dụng cụ",
|
||||
"ui.details_draft_caption": "Các bề mặt được tô màu theo góc so với hướng tháo khuôn.",
|
||||
"ui.details_edit_seam": "Chỉnh sửa đường nối",
|
||||
"ui.details_fixture": "Mẫu thành phần giao diện — chỉ dùng dữ liệu minh họa",
|
||||
"ui.details_fixture_caption": "Mẫu thành phần giao diện với các giá trị minh họa; đây không phải là kết quả của mô hình.",
|
||||
"ui.details_fixture_problem": "Ví dụ kết quả có vấn đề",
|
||||
"ui.details_fixture_readout": "Ví dụ giá trị đo",
|
||||
"ui.details_flip": "Đảo hướng",
|
||||
"ui.details_gap": "Khe hở",
|
||||
"ui.details_hatch": "Gạch các mặt cắt",
|
||||
"ui.details_jump": "Gián đoạn độ cong",
|
||||
"ui.details_key": "Chú giải",
|
||||
"ui.details_offset": "Độ lệch",
|
||||
"ui.details_plane": "Mặt phẳng",
|
||||
"ui.details_pull": "Hướng tháo khuôn",
|
||||
"ui.details_radius": "Bán kính",
|
||||
"ui.details_readout": "Giá trị đo",
|
||||
"ui.details_samples": "Số mẫu",
|
||||
"ui.details_seam": "{body} · Cạnh {edge}",
|
||||
"ui.details_settings": "Thiết lập",
|
||||
"ui.details_sharp_gap": "Sắc cạnh hoặc có khe hở",
|
||||
"ui.details_show_all": "Hiển thị tất cả {count}",
|
||||
"ui.details_smooth": "Trơn mượt",
|
||||
"ui.details_stripes": "Sọc",
|
||||
"ui.details_target": "Điều chỉnh khung nhìn vừa với hình học",
|
||||
"ui.details_worst_seams": "Các đường nối kém nhất",
|
||||
"ui.details_zebra_caption": "Các sọc phản chiếu cho thấy mức độ trơn mượt khi các bề mặt nối với nhau.",
|
||||
"ui.diameter": "Đường kính",
|
||||
"ui.dimension": "Kích thước",
|
||||
"ui.direct_interaction": "Tương tác trực tiếp",
|
||||
@@ -4056,6 +4521,7 @@
|
||||
"ui.edit_in_place_saved_elsewhere": "Chi tiết đã được lưu vào tệp khác; cụm lắp ráp vẫn liên kết với {name}",
|
||||
"ui.edit_in_place_wait": "Hãy chờ những gì đang chạy trong thiết kế hoàn tất",
|
||||
"ui.edit_section_analysis": "Chỉnh sửa phân tích mặt cắt",
|
||||
"ui.edit_sketch_empty": "Không có phác thảo để chỉnh sửa",
|
||||
"ui.ellipse": "Hình elip",
|
||||
"ui.emboss_wrap_note": "Các biên dạng đường trực giao tiếp xúc với một hình trụ được hỗ trợ sẽ tự động quấn. Chọn một thành để chọn mục tiêu.",
|
||||
"ui.end_radius": "Bán kính kết thúc",
|
||||
@@ -4066,12 +4532,15 @@
|
||||
"ui.equation_explicit": "Tường minh",
|
||||
"ui.equation_form": "Dạng",
|
||||
"ui.equation_note": "Biến là một số không có đơn vị: sin(t) hiểu nó theo radian. Kết quả không có đơn vị dùng đơn vị của thiết kế.",
|
||||
"ui.equation_note_range": "Biến là một độ dài, giống như khoảng của nó: có thể kết hợp với tham số độ dài, và chia cho một độ dài khi dùng sin(). Kết quả không có đơn vị sẽ theo đơn vị của thiết kế.",
|
||||
"ui.equation_parametric": "Tham số",
|
||||
"ui.equation_variable_unit": "Biến có đơn vị của khoảng",
|
||||
"ui.equation_x_of_t": "x(t)",
|
||||
"ui.equation_y_of_t": "y(t)",
|
||||
"ui.equation_y_of_x": "y(x)",
|
||||
"ui.equivalent_radius": "Bán kính tương đương",
|
||||
"ui.expand": "Mở rộng",
|
||||
"ui.explode_needs_two_components": "Chế độ xem phân rã tách các cụm chi tiết ra xa nhau, nên thiết kế cần có từ hai cụm chi tiết trở lên (Tạo mới Cụm chi tiết, Chèn thiết kế vào cụm hoặc Tạo cụm chi tiết từ các thân khối)",
|
||||
"ui.exportDxf": "Xuất tệp DXF…",
|
||||
"ui.export_ellipsis_keymap": "Xuất tệp…",
|
||||
"ui.export_keymap_tip": "Xuất phím tắt, danh sách S box yêu thích và thanh công cụ ra tệp",
|
||||
@@ -4240,12 +4709,14 @@
|
||||
"ui.joints": "Các khớp nối",
|
||||
"ui.keyboard_shortcuts": "Phím tắt bàn phím",
|
||||
"ui.language": "Ngôn ngữ (Language)",
|
||||
"ui.lasso_select": "Lasso (kéo một vòng tự do: chọn những gì nằm hoàn toàn bên trong)",
|
||||
"ui.layout_compact": "Gọn",
|
||||
"ui.layout_floating": "Nổi",
|
||||
"ui.length": "Chiều dài",
|
||||
"ui.length_decimals": "Số chữ số thập phân cho chiều dài",
|
||||
"ui.light": "Sáng",
|
||||
"ui.line": "Đoạn thẳng",
|
||||
"ui.line_arc_hint": "Cung tiếp tuyến: nhấp vào điểm cuối của cung. Dừng lại trên điểm cuối cùng để quay lại đường thẳng; nhấp chuột phải hoặc Esc để kết thúc",
|
||||
"ui.link_copies": "Liên kết các bản sao đồng nhất",
|
||||
"ui.link_copies_keep": "Giữ nguyên",
|
||||
"ui.link_copies_link": "Tạo liên kết",
|
||||
@@ -4334,6 +4805,7 @@
|
||||
"ui.part_size_shared": "Dựng lại chi tiết, thay thế mọi tính năng đã thêm. Tất cả các lần xuất hiện của chi tiết này đều được cập nhật.",
|
||||
"ui.paste": "Dán",
|
||||
"ui.path": "Đường dẫn",
|
||||
"ui.pattern_object_type_tip": "Thân khối: các hình đặc, chọn trong khung nhìn hoặc Trình duyệt; mỗi thân được sao chép nguyên vẹn.\nTính năng: các bước trong Lịch sử, như một lần đùn khối hay một lỗ, chọn trong Lịch sử hoặc trên một mặt do chúng tạo ra; bước đó được lặp lại.\nBản phác thảo không phải là cả hai: lặp lại các đường cong của nó bằng Mảng hoặc Lấy đối xứng trong chính bản phác thảo, hoặc đùn khối nó trước.",
|
||||
"ui.pattern_on_path": "Mảng dọc theo đường dẫn",
|
||||
"ui.perforate_margin_default": "theo đường kính",
|
||||
"ui.perforate_pitch": "Bước lỗ",
|
||||
@@ -4360,12 +4832,17 @@
|
||||
"ui.plugins_skipped": "Không thể đọc {count} thư mục.",
|
||||
"ui.plugins_version": "{version}",
|
||||
"ui.point": "Điểm",
|
||||
"ui.point_cloud_add_filter": "Thêm bộ lọc…",
|
||||
"ui.point_cloud_auto_range": "Phạm vi tự động",
|
||||
"ui.point_cloud_color_by": "Tô màu theo",
|
||||
"ui.point_cloud_file_colors": "Màu trong tệp",
|
||||
"ui.point_cloud_filter_by": "Lọc theo",
|
||||
"ui.point_cloud_height_high": "Cao nhất",
|
||||
"ui.point_cloud_height_low": "Thấp nhất",
|
||||
"ui.point_cloud_legend_filter": "Hiện và ẩn trong chú giải ở trên",
|
||||
"ui.point_cloud_no_file_colors": "Tệp không có màu",
|
||||
"ui.point_cloud_pause": "Tạm dừng",
|
||||
"ui.point_cloud_play": "Phát",
|
||||
"ui.point_cloud_single_color": "Một màu",
|
||||
"ui.point_cloud_size": "Kích thước điểm",
|
||||
"ui.point_cloud_units": "Đơn vị của tệp",
|
||||
@@ -4374,6 +4851,11 @@
|
||||
"ui.polygon": "Đa giác",
|
||||
"ui.preferences": "Tùy chọn cài đặt",
|
||||
"ui.press_a_key": "nhấn một phím…",
|
||||
"ui.print_face_cleared": "{body}: đã xóa mặt in",
|
||||
"ui.print_face_input": "Mặt in",
|
||||
"ui.print_face_one_body": "Mặt in được chọn cho một thân: hãy gửi riêng thân đó để thay đổi",
|
||||
"ui.print_face_pick": "Chọn một mặt phẳng của thân đặc để đặt làm mặt in",
|
||||
"ui.print_face_set": "{body}: đã đặt mặt in; Gửi đến Slicer sẽ đặt thân lên mặt này",
|
||||
"ui.profile": "Biên dạng",
|
||||
"ui.profile_plane": "Mặt phẳng biên dạng",
|
||||
"ui.profiles": "Các biên dạng",
|
||||
@@ -4389,6 +4871,7 @@
|
||||
"ui.properties.inertia_y": "Iyx, Iyy, Iyz",
|
||||
"ui.properties.inertia_z": "Izx, Izy, Izz",
|
||||
"ui.properties.measuring": "Đang đo…",
|
||||
"ui.properties.measuring_bodies": "Đang đo… {done} trên {total} thân khối",
|
||||
"ui.properties.measuring_failed": "Phép đo đã dừng trước khi hoàn tất.",
|
||||
"ui.properties.principal_axis": "Trục chính {number}",
|
||||
"ui.properties.principal_moments": "Mômen quán tính chính",
|
||||
@@ -4437,6 +4920,7 @@
|
||||
"ui.revolve": "Xoay tròn tạo khối",
|
||||
"ui.ribbon_exit": "Thoát",
|
||||
"ui.ribbon_labels": "Hiển thị văn bản bên dưới biểu tượng dải băng",
|
||||
"ui.ribbon_menus_skip_pinned": "Không lặp lại các lệnh đã ghim trong menu thả xuống",
|
||||
"ui.ribbon_pin_footer": "Các lệnh đã ghim hiển thị trên ruy-băng. Rê chuột lên một hàng để ghim hoặc bỏ ghim.",
|
||||
"ui.ribbon_workspace": "Không gian làm việc",
|
||||
"ui.right": "Phải (Hình chiếu cạnh)",
|
||||
@@ -4455,6 +4939,7 @@
|
||||
"ui.selectOther": "Chọn đối tượng khác…",
|
||||
"ui.selectTangentChain": "Chọn chuỗi tiếp tuyến",
|
||||
"ui.select_all": "Chọn tất cả",
|
||||
"ui.select_components_by_face": "Chọn thành phần (chọn một mặt sẽ chọn thành phần chứa mặt đó)",
|
||||
"ui.selection": "Vùng chọn",
|
||||
"ui.selection_modifiers": "Phím bổ trợ chọn",
|
||||
"ui.selection_shift_add_only": "Shift+nhấp chỉ thêm, không bỏ chọn",
|
||||
@@ -4496,6 +4981,11 @@
|
||||
"ui.sketch_intersect_selection_filter": "Bộ lọc lựa chọn",
|
||||
"ui.sketch_modifiers": "Phím bổ trợ phác thảo",
|
||||
"ui.sketch_project_geometry": "Hình học",
|
||||
"ui.sketch_report.all_constrained": "Mọi thứ đã được ràng buộc hoàn toàn.",
|
||||
"ui.sketch_report.dof": "Bậc tự do",
|
||||
"ui.sketch_report.loose": "Chưa ràng buộc hoàn toàn",
|
||||
"ui.sketch_report.status": "Trạng thái",
|
||||
"ui.sketch_report.title": "Báo cáo phác thảo",
|
||||
"ui.sketch_scale": "Tỷ lệ phác thảo",
|
||||
"ui.sketches": "Các phác thảo",
|
||||
"ui.slice": "Cắt lát",
|
||||
@@ -4600,10 +5090,19 @@
|
||||
"ui.view_centre": "Tâm góc nhìn",
|
||||
"ui.viewport_status_clear": "Tắt {name}",
|
||||
"ui.viewport_status_clear_hint": "Tắt {name} · Esc",
|
||||
"ui.viewport_status_edges": "{count} cạnh",
|
||||
"ui.viewport_status_from": "từ {direction}",
|
||||
"ui.viewport_status_key": "Hiển thị chú giải cho {name}",
|
||||
"ui.viewport_status_minimum_radius": "Bán kính nhỏ nhất",
|
||||
"ui.viewport_status_pairs": "{count} cặp",
|
||||
"ui.viewport_status_section_hatch": "{setting} · gạch mặt cắt",
|
||||
"ui.viewport_status_section_plane": "Mặt phẳng hiện tại",
|
||||
"ui.viewport_status_section_tilted": "nghiêng · {offset}",
|
||||
"ui.viewport_status_stripes": "{count} sọc",
|
||||
"ui.viewport_status_summary_clear": "Tắt tất cả",
|
||||
"ui.viewport_status_summary_heading": "Trong khung nhìn này",
|
||||
"ui.viewport_status_summary_label": "{name} và {count} mục khác",
|
||||
"ui.viewport_status_summary_more": "+{count}",
|
||||
"ui.viewport_theme_follow": "Theo chủ đề giao diện",
|
||||
"ui.visual_shaded_hidden_edges": "Tô bóng kèm nét khuất",
|
||||
"ui.visual_shaded_with_edges": "Tô bóng kèm hiển thị cạnh",
|
||||
@@ -4640,7 +5139,9 @@
|
||||
"update.button": "Cập nhật",
|
||||
"update.button_version": "Cập nhật lên {version}",
|
||||
"update.check_automatically": "Tự động kiểm tra bản cập nhật",
|
||||
"update.check_for_updates": "Kiểm tra bản cập nhật",
|
||||
"update.check_now": "Kiểm tra ngay",
|
||||
"update.check_unavailable": "Không thể kiểm tra bản cập nhật cho bản cài đặt này.",
|
||||
"update.checking": "Đang kiểm tra…",
|
||||
"update.copy": "Sao chép",
|
||||
"update.dmg_opened": "Ảnh đĩa đã mở và được xác thực: kéo SolidCraft vào thư mục Applications để thay thế bản cũ, sau đó khởi động lại SolidCraft.",
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
"BLEND SURFACE": "混合曲面",
|
||||
"BOUNDARY SURFACE": "边界曲面",
|
||||
"BROWSER": "浏览器",
|
||||
"Back to the original order": "恢复原始顺序",
|
||||
"Ball": "球",
|
||||
"Bar": "扁钢",
|
||||
"Base Center": "底面中心",
|
||||
@@ -595,6 +596,8 @@
|
||||
"Snap to face and edge centres": "捕捉到面和边的中心",
|
||||
"SolidCraft cannot submit reports directly. Submit on GitHub; no token is needed in the app.": "SolidCraft 无法直接提交报告。请在 GitHub 上提交;应用中不需要令牌。",
|
||||
"SolidCraft closed before these designs were saved. Their last autosave can be opened.": "SolidCraft 在这些设计保存前已关闭。可以打开它们的上次自动保存。",
|
||||
"Sort A to Z": "升序排序",
|
||||
"Sort Z to A": "降序排序",
|
||||
"Spacing 2 must be a non-zero number": "间距 2 必须是非零数字",
|
||||
"Spacing must be a non-zero number": "间距必须是非零数字",
|
||||
"Specialise": "专用操作",
|
||||
@@ -775,6 +778,8 @@
|
||||
"at the face": "在面上",
|
||||
"bom.group_children": "子零件并入所属零件的行",
|
||||
"browser.body_name": "实体{number}",
|
||||
"browser.calibrate_click_a": "点击图像选取点 A,或输入其坐标。",
|
||||
"browser.calibrate_click_b": "点击图像选取点 B,或输入其坐标。",
|
||||
"browser.calibrate_title": "校准:{name}",
|
||||
"browser.capture_many": "{count} 个组件已移动,但尚未捕获其位置。",
|
||||
"browser.capture_note": "“捕获位置”保留新位置;“恢复位置”还原原先的位置。",
|
||||
@@ -817,6 +822,8 @@
|
||||
"cmd.appearance_pick_up": "拾取外观",
|
||||
"cmd.appearance_replace": "替换外观",
|
||||
"cmd.assembly_bom": "物料清单",
|
||||
"cmd.assembly_mass_properties": "质量属性",
|
||||
"cmd.body.print_face": "打印底面",
|
||||
"cmd.body_rename": "重命名实体",
|
||||
"cmd.browser_collapse_all": "全部折叠",
|
||||
"cmd.browser_expand_all": "全部展开",
|
||||
@@ -1101,6 +1108,16 @@
|
||||
"cmd.sheet_refold": "重新折弯",
|
||||
"cmd.sheet_rules": "列出钣金规则",
|
||||
"cmd.sheet_unfold": "展开",
|
||||
"cmd.sketch.construction_line": "构造直线",
|
||||
"cmd.sketch.construction_line.angle": "指定角度构造直线",
|
||||
"cmd.sketch.construction_line.bisector": "角平分线",
|
||||
"cmd.sketch.construction_line.horizontal": "水平构造直线",
|
||||
"cmd.sketch.construction_line.parallel": "平行构造直线",
|
||||
"cmd.sketch.construction_line.perpendicular": "垂直构造直线",
|
||||
"cmd.sketch.construction_line.tangent_at": "曲线上点处的切线",
|
||||
"cmd.sketch.construction_line.tangent_external": "过外部点的切线",
|
||||
"cmd.sketch.construction_line.tangent_two": "公切线",
|
||||
"cmd.sketch.construction_line.vertical": "竖直构造直线",
|
||||
"cmd.sketch_arc3d": "三维圆弧",
|
||||
"cmd.sketch_arc_center_point": "中心点圆弧",
|
||||
"cmd.sketch_arc_tangent": "相切圆弧",
|
||||
@@ -1231,6 +1248,7 @@
|
||||
"cmd.view.render_browser": "渲染浏览器",
|
||||
"cmd.view.render_dock": "移动渲染停靠面板",
|
||||
"cmd.view.render_focus": "渲染专注视图",
|
||||
"cmd.view.status_details": "视口状态详情",
|
||||
"cmd.view.status_items": "视口状态项",
|
||||
"cmd.view_ambient_occlusion": "环境光遮蔽",
|
||||
"cmd.view_angle_readout": "视图角度",
|
||||
@@ -1269,8 +1287,14 @@
|
||||
"color.hex_hint": "#rrggbb",
|
||||
"color.hue": "色相",
|
||||
"color.linear": "以 0–1 线性空间显示颜色值",
|
||||
"color.recent": "最近使用的颜色",
|
||||
"color.recent_help": "在任意颜色字段中选择的颜色会显示在这里",
|
||||
"color.saturation": "饱和度(百分比)",
|
||||
"color.saturation_value": "饱和度和明度",
|
||||
"color.selected": "所选颜色",
|
||||
"color.step_down": "减少一步",
|
||||
"color.step_up": "增加一步",
|
||||
"color.value": "明度(百分比)",
|
||||
"config.column_filter_empty": "没有匹配的列",
|
||||
"contact.components_count": "{count} 个组件",
|
||||
"contact.enabled_label": "已启用",
|
||||
@@ -1317,6 +1341,7 @@
|
||||
"dialog.dimension_name": "尺寸:{name}",
|
||||
"dialog.edit_title": "编辑 {title}",
|
||||
"dialog.no_shown_body": "没有可更改的显示实体:请显示一个实体,或选择新建实体",
|
||||
"dialog.pattern_sketch_not_object": "请选择实体或特征:草图两者都不是。请用草图自身的阵列或镜像重复其曲线,或先将其拉伸。",
|
||||
"dialog.select": "↖ 选择",
|
||||
"dialog.selected_count": "↖ 已选择 {count} 个",
|
||||
"dialog.selection_guidance": "选择输入项进行修改。点击已选对象可取消选择;按住 Ctrl/Cmd 点击也可切换选择。检查预览后,再按“确定”。",
|
||||
@@ -1374,26 +1399,243 @@
|
||||
"from the rule": "来自规则",
|
||||
"help.apache": "Apache 许可证 2.0",
|
||||
"help.appearance.assign": "为所选的实体、面或组件设置颜色或材质外观,不改变其重量。用于区分零件或预览表面效果。",
|
||||
"help.assembly.bom": "按零件号列出设计或组件的零件及其数量,并可将清单保存为 CSV 或 JSON。用作采购和装配的物料清单。",
|
||||
"help.attributions": "署名信息 (ATTRIBUTION.md)",
|
||||
"help.build": "版本 {version} · 提交 {commit} · 构建日期 {date}",
|
||||
"help.canvas.decal": "像贴纸一样将图像放到模型的平面上。用于在零件上显示标签、标志或印刷图案。",
|
||||
"help.canvas.edit": "修改画布:位置、大小、角度、不透明度、镜像、可见性或名称。用于将参考图像与在其上描绘的草图对齐。",
|
||||
"help.canvas.insert": "将 PNG 或 JPEG 图像作为半透明参考放在平面或面上。用于按已知尺寸缩放图像后,在草图中描绘照片或图纸。",
|
||||
"help.component.break_link": "断开链接组件与其设计文件的关联,保留其实体不变。用于零件不再需要跟随原文件修改时。",
|
||||
"help.component.capture_position": "将手动移动过的零件的位置确定为其新位置。用于拖动未被接头约束的零件到位之后。",
|
||||
"help.component.create": "向设计添加一个新的空组件,除非另选父级,否则放在当前激活的组件中。用于为装配中的新零件提供存放实体和草图的位置。",
|
||||
"help.component.finish_edit": "保存正在原位编辑的零件,返回其装配体,并用该零件更新装配体。对链接零件的更改完成后使用。",
|
||||
"help.component.from_bodies": "将每个选中的实体变成一个独立的组件,并以实体名称命名。用于把由零散实体构成的设计变成可用接头连接和移动零件的装配。",
|
||||
"help.component.insert_design": "将另一个已保存的设计作为链接到其文件的组件插入,其实体保持在原设计中的位置。用于在装配中复用零件,并通过“更新链接”获取之后的修改。",
|
||||
"help.component.properties": "根据各实体的材料,显示组件的体积、质量、质心和转动惯量。用于检查装配体的重量和平衡。",
|
||||
"help.component.revert_position": "将手动移动过的零件放回原位,放弃尚未捕获的移动。用于撤销装配中的试移动。",
|
||||
"help.component.update_links": "重新读取链接的设计文件,并替换已更改的实体。用于编辑了此装配所使用的零件之后。",
|
||||
"help.config.configure": "将参数、特征、材料或外观添加为配置表的列。用于创建同一设计的变体,例如零件的不同尺寸。",
|
||||
"help.config.preview": "检查配置表的某一行能否重新生成,不改变设计及其历史。用于切换到没有把握的变体之前。",
|
||||
"help.config.rules": "显示配置表的规则、各行以及当前生效的行。用于了解设计的变体是如何设置的。",
|
||||
"help.config.table": "显示配置表:每个变体一行,每个参数或特征一列,并指出设计是否仍与当前生效的行一致。用于检查设计的各个变体。",
|
||||
"help.connect_note": "请重启各个助手以加载 SolidCraft 服务器。每个被修改的文件都已备份为 .bak。",
|
||||
"help.connect_title": "连接 AI 助手",
|
||||
"help.construct.axis.edge": "沿直边或草图线创建构造轴。用作旋转、圆周阵列或接头的轴。",
|
||||
"help.construct.axis.normal_to_face": "创建一条过某点、垂直于面的构造轴。用作从表面笔直伸出的轴。",
|
||||
"help.construct.axis.through_cylinder": "通过圆柱、圆锥或圆环面的中心,或圆形边的中心创建构造轴。用于绕圆形零件旋转或阵列特征。",
|
||||
"help.construct.axis.two_planes": "在两个平面或平整面相交处创建构造轴。用于所需的轴正是两个面之间的交线时。",
|
||||
"help.construct.axis.two_points": "通过两个点、顶点或草图点创建构造轴。用于连接两个已知位置的轴。",
|
||||
"help.construct.plane.along_path": "在边或曲线上的指定位置创建垂直于它的构造平面。用于为扫掠绘制轮廓,或绘制路径的截面。",
|
||||
"help.construct.plane.at_angle": "创建一个由平面或面绕轴或边旋转一定角度而成的构造平面。用于倾斜的草图,例如斜支架。",
|
||||
"help.construct.plane.midplane": "在两个平面或平整面的正中间创建构造平面;若二者成角相交,则取其角平分面。用作镜像的对称面。",
|
||||
"help.construct.plane.offset": "创建与平面或平整面平行的构造平面,按距离或过某点确定。用于在面上方指定高度处绘制草图。",
|
||||
"help.construct.plane.perpendicular": "创建一个包含某直线或边、并垂直于某平面或面的构造平面。用于沿边在模型上垂直地绘制草图。",
|
||||
"help.construct.plane.tangent": "创建在某点与圆柱、圆锥、球或圆环相切的构造平面。用于在圆形零件的侧面绘制草图。",
|
||||
"help.construct.plane.three_points": "通过三个点创建构造平面。用于由模型上的位置(如三个角)确定的平面。",
|
||||
"help.construct.plane.two_edges": "通过位于同一平面内的两条直边或直线创建构造平面。用于穿过零件的平面,例如通过两条相对的边。",
|
||||
"help.construct.point.along_path": "在边或曲线上的指定位置创建构造点。用作路径中途的参考。",
|
||||
"help.construct.point.center": "在圆形边、草图圆或圆弧、球或圆环的中心创建构造点。用作孔、轴和接头的参考。",
|
||||
"help.construct.point.edge_plane": "在边或直线穿过平面或平整面处创建构造点。用于标出路径与平面相交的位置。",
|
||||
"help.construct.point.three_planes": "在三个平面或平整面相交处创建构造点。即使模型上没有顶点,也可用作角点参考。",
|
||||
"help.construct.point.two_edges": "在两条边或直线相交处(或相距最近处)创建构造点。用作虚拟角点处的参考。",
|
||||
"help.construct.point.vertex": "在顶点或草图点上创建构造点。用作参考,即使周围的草图或实体被隐藏也会保留。",
|
||||
"help.contact.check": "列出接触集中在当前位置相互穿透的零件对。用于在驱动接头或运行运动研究之前查找碰撞。",
|
||||
"help.contact.create": "将两个或更多零件组成一个接触集,在接头运动时其实体不会相互穿透。用于接触时应停止的零件,例如抵住限位块的杠杆。",
|
||||
"help.contact.disable_all": "关闭接触,驱动接头和运动研究在零件接触处不再停止。用于重新自由移动零件,或让大型装配保持流畅。",
|
||||
"help.contact.edit": "修改接触集:其包含的零件、名称或是否抑制;也可以删除该接触集。用于调整哪些零件不得相互穿透。",
|
||||
"help.contact.enable_all": "将装配中的所有零件放入同一个接触集,使接头运动时任何两个零件都不会相互穿透。用于快速检查整个机构。",
|
||||
"help.contact.enable_sets": "为已定义的接触集开启接触,驱动接头和运动研究会在其零件即将相互穿透处停止。用于在关闭接触后恢复这些接触集。",
|
||||
"help.contact.list": "列出设计中的接触集、每个接触集包含的零件以及接触是否开启。用于在驱动装配之前检查接触设置。",
|
||||
"help.document.inspect": "显示设计的概览:组件、实体、草图、特征和参数。用于了解不是自己创建的设计。",
|
||||
"help.document.units": "更改设计显示长度所用的单位,如 mm 或英寸。几何大小不变,只有显示和纯数字随之改变。",
|
||||
"help.edit.checkpoint": "记住设计、当前草图和撤销历史的现状。用于尝试有风险的操作之前,以便日后可以回退。",
|
||||
"help.edit.restore_checkpoint": "回到某个检查点,撤销历史一并还原。用于一步丢弃检查点之后的所有操作。",
|
||||
"help.explode.create": "创建爆炸图,将零件从装配中心向外推开,或按设定的位移移动。用于在说明书或演示中展示装配的组装方式。",
|
||||
"help.face.delete": "删除所选的面,并由相邻的面封闭留下的缺口,也可以让缺口保持开放、成为曲面。用于去掉碍事的圆角、孔或凸台。",
|
||||
"help.file.insert_mesh": "将 3MF、STL、OBJ、PLY 或 glTF 文件作为新组件中的网格实体添加到设计中。用于把下载或扫描得到的模型作为参考放在设计旁边。",
|
||||
"help.file.insert_step": "将 STEP、IGES、FreeCAD 或 Rhino 文件作为新组件中的实体添加到设计中;装配中的零件会成为嵌套组件。用于导入供应商或其他 CAD 程序的模型。",
|
||||
"help.file.save_mesh": "将实体保存为 STL、3MF 或 OBJ 网格,曲面的平滑程度可选。用于为 3D 打印或读取网格的程序准备零件。",
|
||||
"help.file.send_to_slicer": "将选中的实体保存为 3MF 文件,并在所选的切片软件中打开。用于一步从模型进入打印。",
|
||||
"help.font_details": "界面使用 egui 的内置字体(Ubuntu Light 和 Hack,采用 Ubuntu Font Licence 和 MIT/Bitstream Vera 许可证;Noto Emoji 和表情图标字体,采用 OFL 和 MIT 许可证)。草图文本使用 Liberation Sans(SIL OFL 1.1)。The Crafting Apps 的可选字体包 craft-fonts(BIZ UDPGothic、Shippori Mincho、BIZ UDMincho、Noto Sans CJK SC、Noto Sans Arabic;SIL OFL 1.1)未随 SolidCraft 构建版本捆绑提供。",
|
||||
"help.fonts": "字体",
|
||||
"help.frame.member": "沿框架草图的线放置型材(如管材或铝型材),每条线一根构件。用于构建框架、货架和焊接结构。",
|
||||
"help.inspect.accessibility": "给刀具从某一方向能够到达和无法到达的面着色。用于检查零件从该方向加工或成型是否可行。",
|
||||
"help.inspect.center_of_mass": "在均匀密度下显示各实体单独以及整体的质心。用于检查平衡和零件的倾倒位置。",
|
||||
"help.inspect.colored_components": "给每个组件一种临时颜色,不改变外观。用于一眼分辨装配体的各个零件。",
|
||||
"help.inspect.compare": "比较两个实体,显示其中一个有而另一个没有材料的位置,并给出体积和偏差。用于对照原件检查修改过或导入的零件。",
|
||||
"help.inspect.continuity": "检查各面沿边相接的平滑程度:间隙、折角或曲率跳变,并给接缝着色。用于找出曲面衔接不干净的地方。",
|
||||
"help.inspect.curvature_comb": "沿曲线、边或面绘制梳状线,梳齿显示弯曲的强弱。用于发现平坦处、折角和曲率不均。",
|
||||
"help.inspect.curvature_map": "按弯曲程度给面着色,半径小的地方为红色。用于找出急弯处并判断曲面是否光滑。",
|
||||
"help.inspect.draft": "按各面相对拔模方向的拔模角着色,标出角度不足的面。用于注塑或铸造前检查零件。",
|
||||
"help.inspect.environment_map": "以反光的镜面效果显示模型。用于根据反射的走向判断曲面的流畅程度。",
|
||||
"help.inspect.interference": "找出相互重叠的实体,并显示每处重叠及其体积。用于检查装配体中是否有零件发生碰撞。",
|
||||
"help.inspect.isocurve": "绘制面的等参线,即曲面所依据的网格。用于查看曲面的走向以及线条密集之处。",
|
||||
"help.inspect.measure": "测量所选对象之间的长度、距离、角度、面积和半径,或实体的体积和质量。用于检查尺寸和间隙。",
|
||||
"help.inspect.minimum_radius": "找出曲线、边或面的最小曲率半径及其位置。用于检查刀具或喷嘴能否沿形状走刀。",
|
||||
"help.inspect.section": "沿平面剖开视图并为截面填充剖面线,不改变模型。用于查看零件和装配体的内部。",
|
||||
"help.inspect.zebra": "在模型的面上显示反射的黑白条纹。用于判断光顺程度:条纹在边处断开或折弯,说明过渡不好。",
|
||||
"help.joint.as_built": "在两个零件当前所在位置将其连接,不移动任何一个,并设定它们仍可如何运动。用于已放置在最终位置的零件。",
|
||||
"help.joint.cam": "将旋转的凸轮与从动件关联,使从动件随凸轮轮廓滑动或摆动。用于凸轮、偏心机构和气门传动。",
|
||||
"help.joint.create": "在所选的接头原点处连接两个零件,并把第二个零件移到位;接头类型决定它们仍可如何运动。用于构建零件像真实机构一样运动的装配。",
|
||||
"help.joint.drive": "在限制范围内设定接头的角度或距离,并带动零件移动;关联的接头和闭环随之运动。用于检查机构是否按预期运动。",
|
||||
"help.joint.gear": "以齿轮传动比关联两个旋转接头,驱动其中一个时另一个随之转动。用于直齿轮和内齿轮,传动比由节圆半径或齿数确定。",
|
||||
"help.joint.limits": "以最小值和最大值设定接头可转动或滑动的范围,或清除这些限制。用于使铰链、滑块或杠杆保持在其实际行程内。",
|
||||
"help.joint.motion_link": "以比例和偏移关联两个接头,驱动其中一个时另一个随之运动。用于“齿轮”“齿轮齿条”或“螺旋”无法表达的接头运动关系。",
|
||||
"help.joint.origin": "在零件上放置一个命名的接头原点:位于面或圆形端部的中心、边的中点、角点或某一点。用于预先确定接头的连接位置;在面上选取的原点会在零件尺寸改变时跟随该面。",
|
||||
"help.joint.rack_pinion": "将旋转的小齿轮与滑动的齿条关联,齿条移动的距离等于小齿轮节圆滚过的弧长。用于齿轮齿条传动、转向机构和直线平台。",
|
||||
"help.joint.reach": "通过在限制范围内改变链上的接头,将零件上的某一点移向目标。用于按末端应到达的位置摆放机构,例如机械臂的末端。",
|
||||
"help.joint.rigid_group": "将选中的零件按当前位置锁定在一起,使其作为一个整体运动。用于彼此之间没有相对运动的成组零件。",
|
||||
"help.joint.screw": "以螺距关联转动与滑动,每转一圈前进相应距离。用于丝杠、螺栓和螺纹轴。",
|
||||
"help.library.apply": "将本地库文件中的材料或外观应用到实体、面或组件。用于重复使用在其他设计中保存的材料。",
|
||||
"help.library.export": "将设计的材料和外观保存到库文件。用于共享,或在其他设计中重复使用。",
|
||||
"help.library.inspect": "检查库文件并列出其中的材料和外观,不改变设计。用于在应用之前查看库里有什么。",
|
||||
"help.licences": "许可证",
|
||||
"help.material.assign": "设置所选实体的材料,例如钢、铝或 ABS。用于让质量和重量与实际零件一致。",
|
||||
"help.material.properties.validate": "检查材料数据卡的数值是否一致、有无缺失。用于在依赖这些数据计算质量或刚度之前。",
|
||||
"help.mesh.convert": "将网格实体(如 STL)重建为带平面和圆柱面的可编辑实体。用于像修改建模实体那样修改导入的机械零件。",
|
||||
"help.mit": "MIT 许可证",
|
||||
"help.motion.study": "在时间轴的各个步骤设定接头值,并以动画方式回放。用于观察机构完成一系列动作,并检查过程中的间隙。",
|
||||
"help.motion.trace": "求出运动研究播放或驱动接头时零件上某一点经过的轨迹,确认后保留为三维草图曲线。用于查看机构的可达范围,或在该轨迹基础上建模。",
|
||||
"help.notice": "NOTICE",
|
||||
"help.occurrence.ground": "将零件固定在原位,或重新解除固定,接头会围绕它移动其他零件。用于装配中其余零件所依托的框架或底座。",
|
||||
"help.occurrence.move": "仅沿关节允许的自由度移动装配零部件。选中零部件的面后,拖动可用的箭头或圆弧。",
|
||||
"help.parameters.change": "打开驱动设计尺寸的命名数值和表达式表。用于在一处修改尺寸,让所有引用它的特征随之更新。",
|
||||
"help.parameters.export": "将设计的参数保存为 CSV 或 JSON。用于在电子表格中编辑,或转移到其他设计。",
|
||||
"help.parameters.graph": "显示哪些参数和特征使用了哪些其他参数和特征,以及其中的循环或错误。用于了解改动某个参数会影响什么。",
|
||||
"help.parameters.import": "将 CSV 或 JSON 中的参数读入设计,要么全部读入,要么一个也不读。用于从电子表格或其他设计带入数值。",
|
||||
"help.parameters.move": "将某个用户参数移到列表中另一个参数之前或之后。用于把相关参数放在一起。",
|
||||
"help.parts.fastener": "按所选尺寸添加标准螺钉、螺栓、螺母、垫圈、销或轴承。放在孔上时会通过接头安装在孔中,无需自己建模紧固件。",
|
||||
"help.parts.insert": "按所选类别、尺寸和长度插入标准零件。放在孔的边缘或孔壁上时,会通过刚性接头安装在孔上。",
|
||||
"help.parts.library": "打开标准零件:标准尺寸的螺钉、螺栓、螺母、垫圈、紧定螺钉、定位销和轴承。用于直接添加标准件,而无需自己建模。",
|
||||
"help.parts.resize": "修改已插入标准零件的尺寸或长度并重建;其接头保持安装位置不变。用于螺钉过长或孔需要其他尺寸时。",
|
||||
"help.plastic.assign_rule": "将塑料规则指定给实体,使其塑料特征默认采用该规则的拔模和间隙。用于一次设置好注塑件的所有特征。",
|
||||
"help.plastic.boss": "在面上添加螺钉凸台:带可选孔、拔模、根部圆角和加强筋的立柱。用于注塑或打印外壳中的螺钉位。",
|
||||
"help.plastic.lip": "沿抽壳实体的边缘添加凸缘或与之配合的凹槽。用于让外壳的两半相互定位并紧密闭合。",
|
||||
"help.plastic.manage_rules": "创建和编辑塑料规则:材料、壁厚、半径、间隙和拔模。用于保持注塑件各特征一致。",
|
||||
"help.plastic.rest": "在面上添加垫块:圆形或矩形的凸垫,可实心或空心,带拔模。用作注塑外壳中的支撑或定位柱。",
|
||||
"help.plastic.snap_fit": "在面上添加卡扣钩,可设置其长度、厚度和卡爪。用于不用螺钉将零件卡在一起。",
|
||||
"help.pointcloud.insert": "将 PLY、XYZ 或 PTS 扫描作为点云插入到模型旁。根据测量数据建模时,可将其用作参考。",
|
||||
"help.sheet.convert": "将厚度均匀的板或抽壳实体转换为钣金实体,在所选的边处折弯。用于让现有零件可以展开。",
|
||||
"help.sheet.export_bend_table": "将钣金实体的折弯表保存为 CSV 或 JSON:角度、半径以及展开图中的折弯位置。用于折弯机或车间。",
|
||||
"help.sheet.export_dxf": "将展开图保存为 DXF,包含轮廓、折弯线和可选的折弯注释。用于激光、等离子或水刀切割。",
|
||||
"help.sheet.flange": "添加法兰:由草图生成的基板、沿开放草图轮廓的壁,或在钣金边上折弯的壁。用于构建钣金零件。",
|
||||
"help.sheet.flat_pattern": "创建钣金实体的展开图,含尺寸、切口和折弯线。用于在切割前检查坯料。",
|
||||
"help.sheet.fold": "沿草图线按指定角度和半径折弯钣金。用于在平板上切好特征之后将其折叠。",
|
||||
"help.sheet.hem": "将钣金边缘折回贴合自身。用于获得安全、坚固且没有锐利毛刺的边缘。",
|
||||
"help.sheet.manage_rules": "创建和编辑钣金规则:厚度、折弯半径、K 因子、释放槽和间隙。用于匹配车间的材料和工具。",
|
||||
"help.sheet.path_flange": "沿钣金边按开放的草图线链添加一串法兰。用于一步生成 U 形或 Z 形等型材。",
|
||||
"help.sheet.perforate": "在整块展开的钣金上添加孔阵,排列为交错或方格。用于通风口、格栅和减重面板。",
|
||||
"help.sheet.refold": "将展开的钣金实体重新折回。用于在展开的钣金上添加特征之后。",
|
||||
"help.sheet.unfold": "展开钣金实体的所有折弯。用于添加需要跨越折弯的孔或切口,之后再重新折弯。",
|
||||
"help.sketch.arc.center_point": "在圆心周围绘制一段圆弧,从起点到终点。适用于圆心已知的情况,例如孔周围或转轴周围的半径。",
|
||||
"help.sketch.arc.tangent": "从直线或圆弧的端点出发,绘制与其相切的圆弧。用于以平滑的弯曲而不是尖角延续链条。",
|
||||
"help.sketch.arc.three_point": "绘制从起点经过第三个点到终点的圆弧。适用于圆弧必须经过给定的点、而不是围绕已知圆心的情况。",
|
||||
"help.sketch.arc3d": "开启3D 草图后,通过三点在空间中绘制精确的圆弧。用于离开草图平面的路径和导轨中的弯曲。",
|
||||
"help.sketch.auto_constrain": "添加草图已近乎满足的约束,例如水平、平行或重合,然后标注尺寸直到完全定义。用于一步锁定画得比较随意的草图。",
|
||||
"help.sketch.auto_constrain_from_datum": "与自动约束类似,但位置是从你选取的基准点而不是原点开始测量。适用于以某个参考点(如角点或孔)布置零件的情况。",
|
||||
"help.sketch.blend_curve": "用与两条曲线都相切的平滑样条曲线连接两者的端点,也可选择曲率连续。用于无折痕地桥接曲线之间的间隙。",
|
||||
"help.sketch.break": "在其他曲线与其相交处,或在你放置的点处,把曲线拆分成若干段。适用于曲线的某一段需要单独约束或单独删除的情况。",
|
||||
"help.sketch.cancel": "离开草图,并放弃自创建或开始编辑以来的所有更改。撤销可恢复这些更改。",
|
||||
"help.sketch.centerline": "在普通直线与中心线之间切换,中心线是轮廓中不包含的轴线。把中心线用作旋转、镜像或对称约束的轴。",
|
||||
"help.sketch.chamfer.distance_angle": "按沿第一条直线的距离和一个角度,对两条直线之间的拐角倒角。适用于图纸以长度加角度给出倒角的情况,例如 2 mm × 30°。",
|
||||
"help.sketch.chamfer.equal_distance": "沿两条直线向后退相同距离,对它们之间的拐角倒角。用于轮廓上常见的 45° 倒角。",
|
||||
"help.sketch.chamfer.two_distance": "按沿每条直线各自的距离,对两条直线之间的拐角倒角。用于以两个长度给出的非 45° 倒角。",
|
||||
"help.sketch.circle.center": "根据圆心和直径绘制圆。用于圆心已知的孔、凸台和其他圆形特征。",
|
||||
"help.sketch.circle.three_point": "绘制经过三个点的圆。适用于圆必须经过给定点的情况,例如已有几何体上的点。",
|
||||
"help.sketch.circle.three_tangent": "绘制与三条直线、圆或圆弧都相切的圆。用于在三条曲线之间放入一个圆,例如三角形的内切圆。",
|
||||
"help.sketch.circle.two_point": "根据直径的两个端点绘制圆。适用于已知圆周上的点而非圆心的情况。",
|
||||
"help.sketch.circle.two_tangent": "绘制指定大小、与两条直线、圆或圆弧相切的圆。用于在两条曲线之间做固定半径的圆角过渡。",
|
||||
"help.sketch.conic": "在两个端点之间绘制圆锥曲线,形状由顶点和 rho 值决定。用于需要调节饱满度的平滑过渡,从平缓到接近尖角都可以。",
|
||||
"help.sketch.constrainer": "应用所选的一两条曲线已近乎满足的约束,例如水平、平行、相切或相等。用于逐个关系地整理手绘草图。",
|
||||
"help.sketch.constraint.coincident": "使一个点位于另一个点、曲线或草图轴上。用于闭合轮廓中的间隙,或把点放到直线上。",
|
||||
"help.sketch.constraint.collinear": "使两条直线位于同一条直线上。用于对齐被打断的边,例如缺口的两侧。",
|
||||
"help.sketch.constraint.concentric": "使两个圆或圆弧具有相同的圆心。用于圆环、沉孔和带台阶的轴。",
|
||||
"help.sketch.constraint.curvature": "使在端点相接的两条曲线以相同的曲率延续 (G2)。用于相切连接不够平滑的地方,例如可见曲面。",
|
||||
"help.sketch.constraint.equal": "使直线长度相等,或使圆和圆弧半径相等。用于让一个尺寸同时驱动多个相同的特征。",
|
||||
"help.sketch.constraint.fix": "把点或曲线固定在当前位置,或再次解除固定。用于拖动或解算草图时不得移动的几何体。",
|
||||
"help.sketch.constraint.horizontal_vertical": "使一条直线或两点之间的连线水平或竖直,取更接近的方向。用于让轮廓与草图坐标轴对齐。",
|
||||
"help.sketch.constraint.midpoint": "把点放在直线的中间,或使两条直线的中点重合。用于使几何体相对于某条边居中。",
|
||||
"help.sketch.constraint.parallel": "使两条直线平行。用于其他尺寸变化时必须保持平行的边。",
|
||||
"help.sketch.constraint.perpendicular": "使两条直线以直角相交。用于不在草图坐标轴上的直线之间的直角拐角。",
|
||||
"help.sketch.constraint.polygon": "把封闭的直线链变成正多边形:各边相等,所有顶点位于同一个圆上。用于让手绘的多边形变成正多边形并保持如此。",
|
||||
"help.sketch.constraint.symmetry": "使两个点或曲线关于一条直线或一个点互为镜像。用于修改一侧时保持轮廓对称。",
|
||||
"help.sketch.constraint.tangent": "使两条曲线相切,例如直线与圆弧。用于无折痕的平滑连接。",
|
||||
"help.sketch.construction": "在普通几何与构造几何之间切换,构造几何不参与轮廓。把构造曲线用作布局、参照和尺寸标注的辅助。",
|
||||
"help.sketch.construction_line": "创建经过两点的无限构造直线,用于辅助绘制草图而不分割轮廓。",
|
||||
"help.sketch.construction_line.angle": "创建与草图X轴成指定角度的无限构造直线。选择一点后输入角度或选择方向。",
|
||||
"help.sketch.construction_line.bisector": "选择两条相交的草图直线,再选择所需的角平分线。结果随原直线的编辑而变化。",
|
||||
"help.sketch.construction_line.horizontal": "创建经过指定点的无限水平构造直线。后续编辑时保持水平约束。",
|
||||
"help.sketch.construction_line.parallel": "选择草图直线,然后放置与其平行的无限构造直线。右键单击可更换参照。",
|
||||
"help.sketch.construction_line.perpendicular": "选择草图直线,然后放置与其垂直的无限构造直线。右键单击可更换参照。",
|
||||
"help.sketch.construction_line.tangent_at": "在圆或圆弧上的点处,或开放样条曲线、圆锥曲线的端点处创建切线。先选曲线,再选接点。",
|
||||
"help.sketch.construction_line.tangent_external": "依次选择圆或圆弧、外部点和所需切线。预览仅显示接点位于已绘圆弧上的解。",
|
||||
"help.sketch.construction_line.tangent_two": "选择两个圆或圆弧,再从预览中选择公切线。接点必须位于已绘曲线上。",
|
||||
"help.sketch.construction_line.vertical": "创建经过指定点的无限竖直构造直线。后续编辑时保持竖直约束。",
|
||||
"help.sketch.copy": "复制所选的草图曲线和点,以及它们之间的约束和尺寸。可粘贴到本草图或另一个草图中。",
|
||||
"help.sketch.create": "在平面或模型的平面上开始新的二维草图。每个拉伸、旋转和扫掠都从草图开始。",
|
||||
"help.sketch.cut": "复制所选的草图几何并将其从草图中删除,只需一步撤销。可粘贴到本草图的其他位置或另一个草图中。",
|
||||
"help.sketch.dimension": "添加驱动尺寸:根据所选对象为长度、距离、角度、半径或直径。输入数值或参数名,草图随之变化。",
|
||||
"help.sketch.edit": "打开已有的草图进行编辑。完成草图后,基于它创建的特征会随之更新。",
|
||||
"help.sketch.ellipse": "根据圆心、长轴端点和短轴一侧的一个点绘制椭圆。用于椭圆形开口、凸轮和其他细长的圆形形状。",
|
||||
"help.sketch.equation_curve": "在一个范围内按公式绘制曲线:x(t) 和 y(t),或 y = f(x)。公式可以使用参数,曲线随参数变化。适用于正弦波、螺旋线或齿轮的渐开线。",
|
||||
"help.sketch.extend": "把直线或圆弧延长到途中最近的曲线,或把两条曲线延伸到相交。用于在修剪或编辑后闭合轮廓中的间隙。",
|
||||
"help.sketch.fillet": "用指定半径的圆弧把两条直线或圆弧相交的拐角倒圆。同时倒圆的多个拐角共用同一个半径。",
|
||||
"help.sketch.finish": "离开草图并返回模型。其封闭轮廓随即可用于拉伸、旋转和其他特征。",
|
||||
"help.sketch.finish_auto_constrain": "对草图运行自动约束,然后完成草图。用于一步得到完全定义的草图。",
|
||||
"help.sketch.fit_curves_to_section": "用草图平面剖切网格或实体,并用直线和圆弧拟合截面。用于把扫描或导入的零件重建为可编辑的草图。",
|
||||
"help.sketch.include_3d": "把模型的边、顶点和其他草图的曲线作为关联参照引入本草图,并把不在其平面上的几何压平到平面上。用于基于不在草图平面内的几何继续作图。",
|
||||
"help.sketch.infinite": "在普通直线与贯穿整个视图的无限构造直线之间切换。用作永远不会过短的布局参照。",
|
||||
"help.sketch.insert_dxf": "将 DXF 图纸中的曲线读入草图,并按设定进行缩放、旋转和放置。用于在其他程序制作的二维图纸(例如激光切割轮廓)基础上建模。",
|
||||
"help.sketch.insert_svg": "将 SVG 图形中的路径读入草图,并按设定进行缩放、旋转和放置。用于把标志或矢量轮廓变成可拉伸的曲线。",
|
||||
"help.sketch.inspect": "打开当前草图的报告:显示剩余的自由度以及是否已完全约束。在完成草图之前,用它找出仍然可以移动的部分。",
|
||||
"help.sketch.intersect": "添加实体、面、边或其他草图与草图平面相交处的曲线或点。它们保持关联,并随模型变化。",
|
||||
"help.sketch.intersection_curve": "在两个实体或面相交处创建与它们关联的三维曲线。用作跟随模型的路径或导轨。",
|
||||
"help.sketch.isoparametric_curve": "通过你选取的点,沿面的 U 或 V 方向创建与该面关联的三维曲线。用作跟随曲面的路径或分割线。",
|
||||
"help.sketch.line": "逐点绘制相连的直线,可以是开放链或封闭轮廓。这是绘制大多数轮廓的基本工具。",
|
||||
"help.sketch.line.midpoint": "从中点向一端绘制直线,另一端随之对称生成。用于以某点为中心的直线,例如对称的边。",
|
||||
"help.sketch.line3d": "开启3D 草图后,在空间中的点之间绘制相连的直线。用于离开草图平面的路径和框架。",
|
||||
"help.sketch.mirror": "把草图曲线和点关于直线或轴镜像,并添加对称约束。用于只画对称轮廓的一半,再将其补全。",
|
||||
"help.sketch.move": "移动或旋转草图曲线和点,或它们的副本。用于在保持形状和约束的同时调整几何的位置。",
|
||||
"help.sketch.offset": "按设定的距离在一侧或两侧创建曲线链的副本。用于壁、轮廓和间隙;距离仍是可编辑的尺寸。",
|
||||
"help.sketch.paste": "把复制或剪切的草图几何粘贴到当前草图。可放置在某一点,或按偏移量移动。",
|
||||
"help.sketch.pattern.circular": "绕中心点复制草图几何,可绕整圆或按设定角度。用于螺栓圆、辐条和齿。",
|
||||
"help.sketch.pattern.rectangular": "按设定间距以行和列复制草图几何。用于孔、槽或通风口的阵列。",
|
||||
"help.sketch.point": "放置一个草图点。用作尺寸、约束、孔心或后续特征的参照。",
|
||||
"help.sketch.point3d": "开启3D 草图后,在空间中放置一个点。用作三维曲线和路径的参照。",
|
||||
"help.sketch.polygon.circumscribed": "在圆外绘制正多边形,大小由中心到边中点的距离决定。适用于已知对边距的情况,例如六角螺母。",
|
||||
"help.sketch.polygon.edge": "根据一条边的两个端点绘制正多边形。适用于已知边的长度和位置的情况。",
|
||||
"help.sketch.polygon.inscribed": "在圆内绘制正多边形,大小由中心到顶点的距离决定。适用于已知对角距的情况。",
|
||||
"help.sketch.project": "把模型的边、面、顶点和其他草图的曲线投影到本草图的平面上并引入。它们保持关联,并随模型变化。",
|
||||
"help.sketch.project_to_surface": "把其他草图的曲线沿本草图的法线方向投影到面上,生成关联的三维曲线。用于把标志、分割线或路径放到曲面上。",
|
||||
"help.sketch.rectangle.center": "根据中心和一个角点绘制矩形。用于以某点(如原点)为中心的轮廓。",
|
||||
"help.sketch.rectangle.rounded": "绘制四个角都倒成同一半径圆角的矩形。用于带圆角的板、盖和开口。",
|
||||
"help.sketch.rectangle.three_point": "根据一条边和对侧的一个点绘制矩形。用于与草图坐标轴成角度的矩形。",
|
||||
"help.sketch.rectangle.two_point": "根据两个对角点绘制矩形。用于板、块体和凹槽的轮廓。",
|
||||
"help.sketch.scale": "以基点为中心按比例缩放草图曲线和点。用于无需重画就调整草图某一部分的大小。",
|
||||
"help.sketch.slot.arc_center": "沿由圆心、起点和终点确定的圆弧,绘制指定宽度的弧形槽。用于绕转轴的调节槽。",
|
||||
"help.sketch.slot.arc_three_point": "沿经过三点的圆弧,绘制指定宽度的弧形槽。适用于槽的路径必须经过给定点的情况。",
|
||||
"help.sketch.slot.center_point": "从中心到一端圆弧的圆心,绘制指定宽度的直槽。用于以某点为中心的槽。",
|
||||
"help.sketch.slot.center_to_center": "在两端圆弧的圆心之间,绘制指定宽度的直槽。用于按中心距标注的槽,例如螺钉调节槽。",
|
||||
"help.sketch.slot.overall": "从一个外端到另一个外端,绘制指定宽度的直槽。适用于槽的总长最重要的情况。",
|
||||
"help.sketch.spline.control_point": "绘制由控制点决定形状的三次样条曲线,曲线不经过这些点。用于通过移动控制点来塑形的平滑流畅曲线。",
|
||||
"help.sketch.spline.control_point_5": "绘制由控制点决定形状的 5 次样条曲线。用于曲线需要以更平滑的曲率连接的地方,例如可见的造型曲面。",
|
||||
"help.sketch.spline.fit_point": "绘制经过你放置的每个点的平滑样条曲线,可开放或封闭。用于通过已知点描出形状。",
|
||||
"help.sketch.spline3d": "开启3D 草图后,在空间中通过各点绘制平滑曲线。用于离开草图平面的扫掠路径和线缆走线。",
|
||||
"help.sketch.spun_profile": "在草图平面中创建实体绕轴旋转时扫出的轮廓。用于获得车削零件的剪影,以便旋转或出图。",
|
||||
"help.sketch.text": "用选定的字体、高度和角度在草图中写文字;文字内容可以跟随参数。拉伸或压印后可做标签和字样。",
|
||||
"help.sketch.transform": "以中心点为基准,一步完成草图几何的缩放、旋转和移动。用于同时调整所选对象的位置和大小。",
|
||||
"help.sketch.trim": "删除你点击位置周围、最近两个交点之间的那段曲线。用于把重叠的线整理成封闭轮廓。",
|
||||
"help.solid.align": "移动所选实体,使其上的点、面或平面与别处的点、面或平面对齐。用于把一个零件贴靠到另一个零件上,而无需测量距离。",
|
||||
"help.solid.boundary_fill": "由相互重叠的工具实体所围成的区域生成实体,只填充所选区域。用于利用多个实体共同围成的空间构建形状。",
|
||||
"help.solid.bounding_solid": "创建包围选中实体的长方体,可设置余量。用于查看零件的总体尺寸,或作为加工所用的毛坯。",
|
||||
"help.solid.box": "根据长、宽、高创建长方体,可从角点或以某点为中心放置。用于快速创建块体、占位体或用于切出特征的实体。",
|
||||
"help.solid.chamfer": "用指定的距离在所选边上切出一个平直的斜面。用于去除锐边,或使销钉、螺钉更容易插入。",
|
||||
"help.solid.coil": "根据直径、圈数、高度或螺距以及圆形或方形截面创建螺旋形实体,例如弹簧。用于弹簧、线圈和螺旋凸筋。",
|
||||
"help.solid.combine": "将多个实体合并、从目标实体中切除,或只保留它们共有的体积,还可以保留工具实体。用于合并零件、用一个形体切割另一个形体,或找出两个实体重叠的位置。",
|
||||
"help.solid.cone": "根据底圆和高度创建圆锥体;若顶面也有半径,则为圆台。用于锥度、漏斗、沉头孔和尖端。",
|
||||
"help.solid.cylinder": "根据半径或直径和高度创建圆柱体,立于某点并沿某轴延伸。用于轴、销、凸台和圆形毛坯。",
|
||||
"help.solid.draft": "将所选的面按指定角度倾斜,角度从中性面量起。用于注塑件或铸件,使零件能够脱模。",
|
||||
"help.solid.emboss": "将文字或标志等草图轮廓从面上凸起或凹入。用于平面或圆柱面上的文字、标签和标记。",
|
||||
"help.solid.extrude": "将草图轮廓按指定距离拉伸为三维形体,可以增加或去除材料。用于把平面轮廓变成方块、凸台或凹槽。",
|
||||
"help.solid.fillet": "用指定半径的平滑圆弧将所选的边倒圆。用于出于强度、手感或外观的考虑而柔化锐边。",
|
||||
"help.solid.hole": "在面上的指定位置钻出指定直径的圆孔。用于螺钉过孔、销孔等简单的圆形开口。",
|
||||
@@ -1402,20 +1644,60 @@
|
||||
"help.solid.move": "按指定的距离和角度移动或旋转所选实体,或其副本。用于调整实体位置,或在别处再生成一个。",
|
||||
"help.solid.offset_face": "将所选的面按指定距离向内或向外推移,周围的面随之调整。用于在不编辑草图的情况下加厚壁、加深凹槽或加高凸台。",
|
||||
"help.solid.pattern.circular": "将所选对象按指定的数量和总角度绕轴重复排列。用于螺栓圆周分布、辐条、散热片和轮齿。",
|
||||
"help.solid.pattern.path": "沿草图路径按数量和间距复制特征或实体。用于沿曲线边的孔,或沿导轨的零件。",
|
||||
"help.solid.pattern.rectangular": "将所选对象按指定的数量和间距沿一个或两个方向重复排列。用于成排或成网格的孔、加强筋、销钉或支脚。",
|
||||
"help.solid.pipe": "沿草图曲线路径创建圆管,可为实心或带壁厚的空心。用于管道、线材、电缆和栏杆。",
|
||||
"help.solid.press_pull": "拖动面来增加或去除材料,或拖动边将其倒圆。用于直接在模型上快速修改。",
|
||||
"help.solid.remove": "从时间线的这一位置起,将所选实体从设计中移除;之前的步骤仍保留它们。用于去掉辅助实体,例如不再需要的切割工具。",
|
||||
"help.solid.replace_face": "将所选的平面移到一个平面或平行的面上,实体随之伸长或缩短。用于让一个面与另一个零件或构造平面齐平。",
|
||||
"help.solid.revolve": "将草图轮廓绕一条轴旋转,生成圆形的实体。用于轴、旋钮、碗等围绕中心线呈圆形的零件。",
|
||||
"help.solid.rib": "沿开放的草图曲线添加一道薄壁,延伸到实体的下一个面。用于加强壁和角,例如注塑件或打印件。",
|
||||
"help.solid.scale": "按比例放大或缩小所选实体,可在各方向相同,也可按轴分别设置。用于调整导入形体的大小,或预留收缩量。",
|
||||
"help.solid.shell": "将实体掏空,留下指定厚度的壁,还可以打开所选的面。用于盒子、盖子等薄壁零件。",
|
||||
"help.solid.sphere": "根据半径或直径,以指定点为球心创建球体。用于球、旋钮和圆头端部。",
|
||||
"help.solid.split_body": "用平面、另一实体的面或草图直线,将实体切分为多个独立的实体。用于制作分别打印、加工或上色的零件。",
|
||||
"help.solid.split_face": "沿平面、另一实体的面或草图曲线分割所选的面,而不切开实体。用于给面的一部分单独设置拔模、颜色或偏移。",
|
||||
"help.solid.sweep": "沿路径拖动草图轮廓生成实体。用于管道、导轨、手柄等截面恒定且沿曲线延伸的零件。",
|
||||
"help.solid.thread": "在圆柱面上添加 ISO 公制螺纹,可作为装饰螺纹或切入实体。用于螺栓、螺纹孔和打印的螺纹零件。",
|
||||
"help.solid.torus": "根据绕轴的大半径和圆形截面的小半径创建圆环。用于 O 形圈、把手和环形凸筋。",
|
||||
"help.solid.web": "沿每条开放的草图曲线各添加一道薄壁,均延伸到实体的下一个面。用于外壳和托盘内部的网格支撑壁。",
|
||||
"help.surface.blend": "创建桥接两个实体边的曲面,与两侧相切连续或曲率连续。用于在间隙上将两个曲面平滑连接。",
|
||||
"help.surface.boundary": "创建填充由二至四条草图曲线构成的环或曲线网络的曲面。用于由边界定义的自由曲面面板。",
|
||||
"help.surface.extend": "将曲面延伸出其边缘,按距离或直至某个平面或面。用于在修剪或缝合之前让曲面相互重叠。",
|
||||
"help.surface.extrude": "将草图曲线或轮廓按一段距离拉伸为曲面,只有壁,没有端盖。用于薄壁,以及切割或分割工具。",
|
||||
"help.surface.fair": "在保持边不动的前提下,使自由曲面的内部变得光顺。用于抚平曲面上的凸起和波浪状反射。",
|
||||
"help.surface.loft": "创建按顺序穿过两个或更多截面的曲面,无端盖。用于外壳以及不同形状之间的过渡。",
|
||||
"help.surface.match": "重建曲面的边,使其与另一实体的边衔接,并匹配相切或曲率。用于平滑地闭合两个曲面之间的接缝。",
|
||||
"help.surface.offset": "将面沿法向按一定距离复制为新的曲面实体。用于蒙皮、间隙,或壁的另一侧。",
|
||||
"help.surface.patch": "用平面或平滑弯曲的面填充草图区域或边的闭合环。用于封闭曲面实体上的孔。",
|
||||
"help.surface.reverse_normal": "翻转曲面实体的面,使其外侧朝向反方向。用于面朝内时,在加厚或缝合之前。",
|
||||
"help.surface.revolve": "将草图曲线或轮廓绕轴旋转为曲面,无端盖。用于灯罩、碗、喷嘴等圆形壳体。",
|
||||
"help.surface.ruled": "从一串边出发,沿面的法向、切向或按某一角度生成由直线构成的带状面。用于拔模壁、过渡面和分型面。",
|
||||
"help.surface.stitch": "沿共用的边将曲面实体缝合在一起,闭合时成为实体。用于将一组曲面变成一个实体。",
|
||||
"help.surface.sweep": "沿路径移动草图曲线或轮廓生成曲面,无端盖。用于排水槽、饰条等沿路径延伸的薄形状。",
|
||||
"help.surface.thicken": "为曲面实体赋予厚度,使其成为实体。用于由曲面制作可打印或可加工的零件。",
|
||||
"help.surface.trim": "用平面、另一个曲面或草图曲线切割曲面,并保留所选的一侧。用于在缝合前将曲面切成所需形状。",
|
||||
"help.surface.unstitch": "将实体的面分离为各自独立的曲面实体;实体会拆成曲面。用于重新处理实体中的单个面。",
|
||||
"help.surface.untrim": "去掉面上的孔,或将其外边界恢复为曲面的自然边界。用于在修剪之后找回完整的曲面。",
|
||||
"help.third_party": "第三方许可证",
|
||||
"help.timeline.compute_all": "从头重新计算时间线中的所有特征。用于刷新模型,并查看哪些特征失败。",
|
||||
"help.timeline.delete": "从时间线中删除所选特征;删除草图时,由它生成的特征也会一起删除。用于去掉不再需要的步骤。",
|
||||
"help.timeline.dependents": "列出会随某个特征一同被删除的特征,以及缺少它就会失败的特征。用于在删除或更改特征之前。",
|
||||
"help.timeline.play": "逐个播放剩余特征,每次重建后暂停半秒。再次运行此命令或按Escape停止;转到末尾会立即跳转。",
|
||||
"help.view.apply": "将视图转到前视、俯视、等轴测等标准方向,或转到已保存的命名视图。用于从固定角度观察模型。",
|
||||
"help.view.delete": "删除已保存的命名视图。模型不会改变。",
|
||||
"help.view.fit": "缩放并平移,使整个模型或所选对象充满视图。用于模型跑出视野时。",
|
||||
"help.view.grid": "显示或隐藏视口中的网格。用作建模时的尺寸和方向参考。",
|
||||
"help.view.ground_shadow": "显示或隐藏模型在地面上的阴影。用于更容易判断高度和位置。",
|
||||
"help.view.home": "将视图转回主视图方向并适合模型。用于快速回到已知的视图。",
|
||||
"help.view.list": "列出设计中保存的命名视图。用于找到之前保存的视图。",
|
||||
"help.view.navigate": "按步骤旋转、平移或缩放视图,例如向左转四分之一圈。用于精确移动相机,而不是靠拖动。",
|
||||
"help.view.navigation_bar": "显示或隐藏视口底部的导航栏。隐藏可腾出空间,显示便于用鼠标使用视图工具。",
|
||||
"help.view.rename": "为已保存的命名视图改名。视图本身保持不变。",
|
||||
"help.view.save": "将当前相机位置作为命名视图保存到设计中。用于以后回到同一角度,例如截图。",
|
||||
"help.view.spin": "让视图持续绕模型环绕,直到下一次点击或按键。用于从各个方向展示模型。",
|
||||
"help.view.tool": "锁定一个相机工具(环绕、平移或缩放),之后用鼠标左键拖动即可移动视图,直到关闭。用于触控板或没有鼠标中键时。",
|
||||
"help.view.visual_style": "切换模型的绘制方式:带边或不带边的着色、线框,或带隐藏边。用线框看内部,用着色得到干净的外观。",
|
||||
"history.sketch_under_constrained": "欠约束({count} 个自由度)",
|
||||
"history.sketch_under_constrained_one": "欠约束({count} 个自由度)",
|
||||
"hole_presets.confirm_delete": "确认删除",
|
||||
@@ -1592,6 +1874,10 @@
|
||||
"material.selection.mixed": "不同材料",
|
||||
"measure.at": "位置",
|
||||
"measure.item": "项目 {number}",
|
||||
"measure.quick_copied": "已复制测量值",
|
||||
"measure.quick_copy": "点击复制测量值",
|
||||
"measure.quick_edges": "{count} 条边",
|
||||
"measure.quick_faces": "{count} 个面",
|
||||
"messages.ago_h": "{n} 小时前",
|
||||
"messages.ago_min": "{n} 分钟前",
|
||||
"messages.ago_s": "{n} 秒前",
|
||||
@@ -1625,6 +1911,7 @@
|
||||
"nav.hfss.help": "Alt+左键拖动平移,Shift+Alt+左键拖动缩放,在空白处 Ctrl+左键拖动旋转",
|
||||
"nav.inventor.help": "中键拖动平移,Shift+中键拖动旋转,Ctrl+中键拖动缩放,右键拖动旋转",
|
||||
"nav.maya.help": "Alt+左键拖动旋转,Alt+中键拖动平移,Alt+右键拖动缩放;中键拖动也可平移",
|
||||
"nav.nx.help": "中键拖动旋转,Shift+中键平移(对应 NX 的中键+右键),Ctrl+中键缩放(对应 NX 的中键+左键);右键拖动不旋转视图",
|
||||
"nav.openscad.help": "在空白处左键拖动旋转,Shift+左键拖动框选,拖动草图几何可编辑;右键或中键拖动平移,Shift+右键或 Shift+中键拖动缩放",
|
||||
"nav.perspective.sketch": "编辑草图时使用正交视图。完成草图后才能切换透视。",
|
||||
"nav.right_drag_orbits.help": "关闭:右键拖动不会移动相机,右键只打开上下文菜单。选择 SolidWorks 鼠标映射时会关闭此项。",
|
||||
@@ -1744,6 +2031,11 @@
|
||||
"not a move": "不是移动",
|
||||
"not a number": "不是数字",
|
||||
"open a sketch first": "请先打开一个草图",
|
||||
"parameters.apply_live": "离开字段时立即应用每项更改",
|
||||
"parameters.apply_live_tip": "关闭时:更改会等到“应用”或“确定”,然后设计只为所有更改重建一次。“取消”或 Esc 会放弃这些更改。",
|
||||
"parameters.held": "{count} 项更改等待应用",
|
||||
"parameters.held_hint": "编辑表达式和单位。更改将等到“应用”或“确定”时生效。",
|
||||
"parameters.held_one": "1 项更改等待应用",
|
||||
"parts.automatic_name": "自动",
|
||||
"parts.dimension.across_flats": "对边宽度",
|
||||
"parts.dimension.bore": "内径",
|
||||
@@ -1766,6 +2058,8 @@
|
||||
"parts.family.set_screw": "内六角平端紧定螺钉",
|
||||
"parts.family.socket_head_cap_screw": "内六角圆柱头螺钉",
|
||||
"parts.family.washer": "平垫圈",
|
||||
"parts.holes": "孔(可选)",
|
||||
"parts.placement_hint": "选择一个或多个孔,在每个孔中各装一个零件;或按确定将其放在原点",
|
||||
"pattern.alignment_2": "对齐 2",
|
||||
"pattern.alignment_hint": "数量包含原始图形。居中时副本分布在两侧;数量为偶数时,反转可切换多一个副本的一侧。",
|
||||
"pattern.direction_1": "方向 1",
|
||||
@@ -1818,6 +2112,8 @@
|
||||
"prefs.bottom_centre": "底部居中",
|
||||
"prefs.bottom_right": "右下角",
|
||||
"prefs.browser": "浏览器",
|
||||
"prefs.browser_eye_left": "显示切换位于折叠箭头旁",
|
||||
"prefs.browser_eye_left_note": "浏览器各行的显示切换像以前一样位于折叠箭头旁,而不是在行右端的一列中。",
|
||||
"prefs.browser_reveal_on_hover": "悬停时显示",
|
||||
"prefs.browser_show_note": "“显示”让浏览器始终留在屏幕上。“悬停时显示”会将其隐藏,直到指针移到它的位置或其左边缘的细标签上;指针在其中或其菜单打开时,它保持打开。",
|
||||
"prefs.browser_shown": "显示",
|
||||
@@ -1837,6 +2133,8 @@
|
||||
"prefs.ctrl_cmd": "Ctrl / Cmd",
|
||||
"prefs.curved_surfaces": "曲面",
|
||||
"prefs.curves": "曲面",
|
||||
"prefs.dark_parts_shading": "保持深色零件的形状",
|
||||
"prefs.dark_parts_shading_help": "以线性光照和柔和的天空补光着色视图,使深色面保留渐变而不变成一片黑色",
|
||||
"prefs.dead_zone_note": "斜线区域为死区:此范围内的移动将被忽略。",
|
||||
"prefs.default": "默认",
|
||||
"prefs.design": "设计默认值",
|
||||
@@ -1851,6 +2149,8 @@
|
||||
"prefs.edges": "边缘与着色",
|
||||
"prefs.extend": "扩展",
|
||||
"prefs.extra_navigation": "在空白处按住Ctrl并用鼠标左键拖动可旋转;按住空格键可平移。",
|
||||
"prefs.extrude_view_isometric": "打开拉伸时转到等轴测视图",
|
||||
"prefs.extrude_view_return": "关闭拉伸时回到之前的视图",
|
||||
"prefs.follows_os": "跟随操作系统",
|
||||
"prefs.font": "字体",
|
||||
"prefs.font_fallback": "所选字体缺少的字符会使用内置字体,避免标签显示为空方框。",
|
||||
@@ -1866,8 +2166,11 @@
|
||||
"prefs.graphics_card_auto": "自动",
|
||||
"prefs.graphics_card_missing": "已保存的显卡不可用;将使用自动选择。",
|
||||
"prefs.graphics_card_restart": "重启 SolidCraft 后生效。WGPU_ADAPTER_NAME 优先于此选择。",
|
||||
"prefs.graphics_card_unused": "已保存的显卡未用于此窗口;实际使用的显卡显示在“帮助 › 关于”和状态栏中。请尝试“自动”,或将 WGPU_ADAPTER_NAME 设为显卡名称中的唯一部分。",
|
||||
"prefs.graphics_note": "在速度与平滑度之间取舍。每个选项均以示例展示效果。",
|
||||
"prefs.graphics_presets_note": "预设会同时设置以下选项。",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out": "缩小时隐藏约束符号",
|
||||
"prefs.hide_constraint_glyphs_zoomed_out_note": "草图缩小到一定程度时隐藏约束符号,以免遮挡草图。关闭:任意缩放比例下符号仍保持固定屏幕大小。",
|
||||
"prefs.history": "历史",
|
||||
"prefs.history_origin_bodies": "在顶部显示原点和实体",
|
||||
"prefs.history_origin_bodies_note": "左侧或浏览器下方的历史以活动组件的实体文件夹和原点开头,并带有与浏览器相同的显示切换和菜单。底部的历史保持不变。",
|
||||
@@ -1878,6 +2181,8 @@
|
||||
"prefs.history_sketches_note": "草图:选择“位于其特征下”后,左侧历史在宽度足以显示名称时,会将草图缩进一级,列在由其创建的第一个特征下。底部时间轴始终保持创建顺序。",
|
||||
"prefs.history_sketches_under_feature": "位于其特征下",
|
||||
"prefs.hold_stop_snapping": "按住以停用吸附",
|
||||
"prefs.home_fit_size": "主视图与适配大小",
|
||||
"prefs.home_fit_size_note": "主视图、适配、打开的设计或视图导航器切换视图框住模型时,模型占视图的比例,与下方设置是否开启无关。100 %:填满面板、罗盘和导航栏之间的视图。",
|
||||
"prefs.icons_only": "仅图标",
|
||||
"prefs.imported_file": "已导入文件",
|
||||
"prefs.in_browser": "在浏览器中",
|
||||
@@ -1886,13 +2191,20 @@
|
||||
"prefs.interface_language": "界面语言",
|
||||
"prefs.interface_note": "SolidCraft 的外观和面板布局。",
|
||||
"prefs.interval_minutes": "{n} 分钟",
|
||||
"prefs.invert_navigator_arrows": "反转视图立方体的旋转箭头",
|
||||
"prefs.invert_navigator_arrows_note": "立方体周围的箭头按箭头所指的方向转动相机,与 Fusion 和 Inventor 相同:左侧箭头指向右,相机向右转动。关闭:箭头把立方体转向它所在的那一面,因此左侧箭头使相机向左转动。弯曲的翻滚箭头不受影响。",
|
||||
"prefs.keep_work_on_tab_switch": "切换设计时保持对话框和工具打开",
|
||||
"prefs.keep_work_on_tab_switch_note": "每个设计标签页保留其打开的对话框或工具(包括其中已选择和输入的内容)以及工具栏选项卡。回到该设计时它们仍在原处。关闭时:切换设计会取消它们并显示“模型”选项卡。",
|
||||
"prefs.labels": "标签",
|
||||
"prefs.language_system": "系统",
|
||||
"prefs.layout": "布局",
|
||||
"prefs.layout_note": "紧凑模式将面板停靠在窗口边缘。浏览器半透明仅适用于浮动模式。助手面板的位置在助手页面中设置。",
|
||||
"prefs.left": "左侧",
|
||||
"prefs.left_click": "左键单击",
|
||||
"prefs.line_drag_draws_one": "按下并拖动绘制一条直线",
|
||||
"prefs.line_drag_draws_one_note": "在直线工具中,按下、拖动再松开,会从按下处到松开处绘制一条直线并在此结束。单击仍会绘制连续的直线。关闭时:拖动与单击一样,在松开处放置一个点。",
|
||||
"prefs.line_hover_tangent_arc": "停留在直线的最后一点上以切换到相切圆弧",
|
||||
"prefs.line_hover_tangent_arc_note": "在直线工具中,画好一段后,先离开连续线的最后一点,再回到该点并让指针保持不动:下一次单击将确定相切圆弧的终点,同样的操作可切回直线。关闭:停留在该点不起作用。",
|
||||
"prefs.linked_designs": "链接设计",
|
||||
"prefs.live_input": "实时输入",
|
||||
"prefs.live_preview": "实时预览",
|
||||
@@ -1906,6 +2218,9 @@
|
||||
"prefs.max_file_size_step": "STEP 和导入文件",
|
||||
"prefs.max_file_size_web": "网页版可打开最大 512 MB 的 STEP 和导入文件,以及最大 256 MB 的设计:浏览器标签页无法容纳更大的文件。桌面版可提高这些上限。",
|
||||
"prefs.megabytes": "MB",
|
||||
"prefs.menu_grid": "大图标",
|
||||
"prefs.menu_list": "列表",
|
||||
"prefs.menus": "菜单",
|
||||
"prefs.minutes": "分钟",
|
||||
"prefs.minutes_suffix": " min",
|
||||
"prefs.mouse": "鼠标与触控板",
|
||||
@@ -1913,6 +2228,8 @@
|
||||
"prefs.mouse_mapping": "鼠标映射",
|
||||
"prefs.navigation": "导航",
|
||||
"prefs.navigation_note": "鼠标、触控板和3D鼠标如何移动视图。",
|
||||
"prefs.navigator_fit": "视图导航器切换视图后适配模型",
|
||||
"prefs.navigator_fit_note": "点击立方体的面、角或箭头,或坐标轴指示器的轴时,也会从各个方向都能容纳模型的同一距离(其包围球)注视模型中心。开启期间主视图使用相同的缩放和中心,因此之后选择的视图只改变方向。关闭:视图原地旋转,保持目标点和缩放。",
|
||||
"prefs.network_host_remove": "删除",
|
||||
"prefs.network_locations": "允许设计中的网络位置",
|
||||
"prefs.network_locations_note": "关闭:设计中位于其他计算机 (\\\\server\\share) 上的链接文件,只会从此处列出的服务器打开,或在询问时你允许的服务器打开。",
|
||||
@@ -1925,10 +2242,16 @@
|
||||
"prefs.origin_plane_names": "原点平面名称",
|
||||
"prefs.origin_plane_names_note": "浏览器、对话框和列表中显示的名称。{top} 即 XY,{front} 即 XZ,{right} 即 YZ(Z 轴朝上)。命令、脚本和已保存的设计仍使用 XY、XZ 和 YZ。",
|
||||
"prefs.overall_speed": "整体速度",
|
||||
"prefs.parameter_list_rows": "参数列表行数",
|
||||
"prefs.parameter_list_rows_tip": "在空的数值框中按下箭头会列出参数(收藏的在前),最多列出此数量。数量越少,大型设计中的列表越轻。",
|
||||
"prefs.persistent_ribbon_pressed": "突出显示已启用的功能区命令",
|
||||
"prefs.persistent_ribbon_pressed_help": "在效果启用时突出显示相应的功能区命令。关闭此选项可保留原来的中性外观和命令帮助。",
|
||||
"prefs.perspective_fov": "视场角",
|
||||
"prefs.placement": "放置",
|
||||
"prefs.prefer_free_sketch_points": "草图点重合时优先选择可移动的点",
|
||||
"prefs.preview_choices": "所选设置预览",
|
||||
"prefs.print_face_highlight": "打印底面高亮",
|
||||
"prefs.print_face_highlight_tip": "视图中实体打印底面的着色和轮廓强度。0 % 不显示高亮。",
|
||||
"prefs.profile_active": "当前配置文件",
|
||||
"prefs.profile_applied": "已应用配置文件。",
|
||||
"prefs.profile_changed": "保存配置文件后设置已更改。“保存”会将其写入配置文件。",
|
||||
@@ -1950,9 +2273,13 @@
|
||||
"prefs.quality_fastest": "最快",
|
||||
"prefs.quality_slowest": "最慢",
|
||||
"prefs.quality_smoother": "更平滑",
|
||||
"prefs.quick_measure": "在视图角落显示快速测量",
|
||||
"prefs.quick_measure_note": "在视图右下角、历史记录上方显示所选对象的尺寸:边的长度(圆形边显示 Ø 和 R)、面的面积、点的位置、两个对象之间的距离和角度、多条边或多个面的总和。点击即可复制。",
|
||||
"prefs.render_previous_geometry_budget": "使用先前的渲染预览几何内存预算",
|
||||
"prefs.render_previous_geometry_budget_help": "恢复先前的固定几何内存上限(64位桌面为512 MiB,其他平台为128 MiB),替代基于设备的预算。",
|
||||
"prefs.reports_saved": "已保存 {n} 份",
|
||||
"prefs.ribbon_click_ends_tool": "单击正在运行的工具的按钮将结束该工具",
|
||||
"prefs.ribbon_click_ends_tool_note": "单击正在使用的草图工具的高亮功能区按钮会结束该工具,在视图中单击即可再次选择。关闭:单击会重新启动该工具。",
|
||||
"prefs.ribbon_reveal": "在功能区中显示搜索结果",
|
||||
"prefs.ribbon_reveal_note": "将指针悬停在“搜索命令”的结果上时,会显示该命令在功能区中的位置:其选项卡、按钮或面板下拉菜单中的行。从搜索启动的命令会在那里闪烁,从下拉菜单运行的命令会标记其面板。",
|
||||
"prefs.right_click": "右键单击",
|
||||
@@ -1963,6 +2290,8 @@
|
||||
"prefs.search_empty": "没有匹配的设置",
|
||||
"prefs.select": "选择",
|
||||
"prefs.select_one_item": "选择一个项目",
|
||||
"prefs.select_other_hidden": "使用“选择其他”选择隐藏几何体",
|
||||
"prefs.select_other_hidden_help": "开启:包括指针附近的隐藏实体、草图和被遮挡的边。关闭:恢复原来的列表,仅包含指针正下方的可见几何体。",
|
||||
"prefs.selecting": "选择",
|
||||
"prefs.shift": "Shift",
|
||||
"prefs.shift_add_ctrl_toggle": "Shift 仅添加;Ctrl / Cmd 切换选择",
|
||||
@@ -1974,11 +2303,18 @@
|
||||
"prefs.sketch_align_points_note": "绘制时,点可同时与一个草图点水平对齐、与另一个草图点竖直对齐,并显示虚线参考线;单击后保留两个对齐约束。关闭:仅与上一点对齐,每次一个方向。",
|
||||
"prefs.sketch_conflict_colour": "以冲突颜色显示冲突的几何图形",
|
||||
"prefs.sketch_conflict_colour_note": "草图约束冲突时,不仅失败约束的符号或尺寸,该约束所约束的曲线和点也以冲突颜色绘制。关闭:它们保持平常的颜色。",
|
||||
"prefs.sketch_construction_lines": "扩展构造直线工具",
|
||||
"prefs.sketch_exit_view": "草图结束时的视图",
|
||||
"prefs.sketch_exit_view.keep": "保持当前视图",
|
||||
"prefs.sketch_exit_view.previous": "返回之前的视图",
|
||||
"prefs.sketch_exit_view.unless_rotated": "未旋转时返回",
|
||||
"prefs.sketch_exit_view_note": "“完成草图”、取消或连按两次 Esc 后视图的去向。",
|
||||
"prefs.sketch_face_activates_part": "在零件的面上绘制草图时激活该零件",
|
||||
"prefs.sketch_face_activates_part_note": "在另一个组件的实体面上开始的草图会先激活该组件,因此草图属于它,并在浏览器中留在该零件下。之后该零件保持激活。关闭时:草图属于当前激活的组件。",
|
||||
"prefs.sketch_open_look_at": "打开草图时转向正对草图",
|
||||
"prefs.sketch_open_look_at_note": "关闭:创建或编辑草图时视图保持不变。需要时用“朝向”正对草图。",
|
||||
"prefs.sketch_recent_snap": "自动吸附到最近的圆心和中点",
|
||||
"prefs.sketch_recent_snap_note": "绘图时,将光标吸附到最近两个圆心或直线边中点的辅助线相交处。关闭:辅助线仅作显示,光标不会移动。",
|
||||
"prefs.sketch_selection": "草图与选择",
|
||||
"prefs.sketch_selection_heading": "草图和选择",
|
||||
"prefs.sketch_selection_note": "草图如何捕捉,以及单击如何选择。",
|
||||
@@ -1988,6 +2324,8 @@
|
||||
"prefs.sketch_tab_always_note": "未打开草图时,草图选项卡也保留在功能区中紧随模型之后。其中的绘图工具会先在所选平面或面上(否则在接下来选取的平面上)创建草图,并在其中准备好该工具。",
|
||||
"prefs.sketch_tracking_guides": "圆心和中点对齐辅助线",
|
||||
"prefs.sketch_tracking_guides_note": "将光标悬停在圆心或直线边的中点,然后水平或垂直移动以显示临时虚线辅助线。",
|
||||
"prefs.sketch_tracking_points": "绘制时也从端点和角点显示对齐辅助线",
|
||||
"prefs.sketch_tracking_points_note": "绘图工具等待点时,将光标悬停在直线或圆弧的端点、矩形的角点或独立点上,会显示与圆心或中点相同的临时虚线辅助线。关闭:仅圆心和中点。",
|
||||
"prefs.sketching": "草图",
|
||||
"prefs.snap_drawing_note": "在绘制或拖动草图点时使用。",
|
||||
"prefs.source": "来源",
|
||||
@@ -2004,6 +2342,24 @@
|
||||
"prefs.status_error": "错误",
|
||||
"prefs.status_selected": "已选择",
|
||||
"prefs.status_warning": "警告",
|
||||
"prefs.structure.appearance": "外观",
|
||||
"prefs.structure.appearance_note": "颜色、文字和无障碍。",
|
||||
"prefs.structure.in_profile": "包含在配置中",
|
||||
"prefs.structure.layout": "布局",
|
||||
"prefs.structure.layout_note": "窗口各部分的位置。",
|
||||
"prefs.structure.look": "外观",
|
||||
"prefs.structure.measure_pointer": "测量和指针",
|
||||
"prefs.structure.mouse3d": "3D 鼠标",
|
||||
"prefs.structure.mouse3d_note": "SpaceMouse 和 SpaceNavigator。",
|
||||
"prefs.structure.navigation_note": "鼠标和触控板。3D 鼠标有单独的页面。",
|
||||
"prefs.structure.profile": "配置",
|
||||
"prefs.structure.profile_edited": "保存后已更改",
|
||||
"prefs.structure.profile_hover": "保存在设置配置中",
|
||||
"prefs.structure.scale_percent": "{percent}%",
|
||||
"prefs.structure.sketch": "草图",
|
||||
"prefs.structure.tools": "工具",
|
||||
"prefs.structure.tools_note": "建模工具的行为。",
|
||||
"prefs.structure.work": "工作",
|
||||
"prefs.supersampling_brief": "以更高分辨率绘制后滤波缩小:更清晰,但负载更高。",
|
||||
"prefs.tab_accent_note": "强调色跟随当前选项卡",
|
||||
"prefs.theme_file": "主题文件",
|
||||
@@ -2015,6 +2371,16 @@
|
||||
"prefs.theme_follow_off": "关闭",
|
||||
"prefs.theme_follow_stop": "停止跟随",
|
||||
"prefs.theme_import_hint": "单击选择主题文件,拖放到此处,或复制主题后按 Ctrl+V(Mac 上为 Cmd+V)",
|
||||
"prefs.theme_option_opacity": "不透明度",
|
||||
"prefs.theme_option_opacity_help": "调整浮动面板的不透明度。最低不透明度限制可确保文字在视口颜色上清晰可读。",
|
||||
"prefs.theme_option_tab_colours": "选项卡颜色",
|
||||
"prefs.theme_option_tab_colours_help": "为每个功能区选项卡使用主题的面板和视口颜色。",
|
||||
"prefs.theme_option_tab_fade_ms": "选项卡过渡",
|
||||
"prefs.theme_option_tab_fade_ms_help": "切换选项卡时渐变面板和视口颜色。设为零可立即切换。",
|
||||
"prefs.theme_options_badge": "选项",
|
||||
"prefs.theme_options_more": "更多 · {count}",
|
||||
"prefs.theme_options_reset": "重置",
|
||||
"prefs.theme_options_unavailable": "此设备不支持",
|
||||
"prefs.theme_paste": "粘贴主题",
|
||||
"prefs.theme_paste_none": "剪贴板中没有 SolidCraft 主题",
|
||||
"prefs.timeline_half_hour": "−30 分钟",
|
||||
@@ -2036,13 +2402,23 @@
|
||||
"prefs.under_cursor": "光标下方",
|
||||
"prefs.units_precision": "单位与精度",
|
||||
"prefs.updates": "更新",
|
||||
"prefs.value_boxes_in_view": "在视图中于手柄旁显示数值",
|
||||
"prefs.value_boxes_in_view_tip": "命令的数值(距离、半径等)显示在模型上方手柄旁的框中。关闭后,在命令窗口中输入数值,选取后键盘输入会进入该窗口,模型不会被遮挡。",
|
||||
"prefs.view": "视图行为",
|
||||
"prefs.view_confirm_corner": "在视图角落显示确定和取消",
|
||||
"prefs.view_confirm_corner_note": "打开对话框或草图时,视图右上角的勾号和叉号与对话框的确定和取消作用相同,或完成和取消草图。视图导航器会下移到它们下方。",
|
||||
"prefs.viewport": "视口",
|
||||
"prefs.viewport_analysis_status": "显示视口分析状态",
|
||||
"prefs.viewport_analysis_status_help": "在视口上方显示启用的分析,从各项目打开图例,并按 Esc 关闭最近启用的分析。关闭此选项可恢复角落图例和原来的 Esc 行为。",
|
||||
"prefs.viewport_background": "背景",
|
||||
"prefs.viewport_background_colour": "颜色",
|
||||
"prefs.viewport_background_theme": "主题渐变",
|
||||
"prefs.viewport_section_status": "显示视口剖面状态",
|
||||
"prefs.viewport_section_status_help": "在视口中显示剖面设置。按 Escape 或单击活动的功能区按钮可关闭剖面。禁用以保留原有剖面控件。",
|
||||
"prefs.viewport_status_details": "视口实时详情",
|
||||
"prefs.viewport_status_details_help": "在标准详情卡片中编辑当前分析和剖面设置。禁用后恢复只读分析图例和剖面对话框。",
|
||||
"prefs.viewport_status_summary": "汇总视口状态项",
|
||||
"prefs.viewport_status_summary_help": "将三个或更多视口状态项折叠为一个汇总徽章。禁用后,所有项目仍显示在完整的一行中。",
|
||||
"prefs.wheel": "滚轮",
|
||||
"prefs.wheel_trackpad": "滚轮与触控板",
|
||||
"prefs.workspace": "工作区",
|
||||
@@ -2052,6 +2428,10 @@
|
||||
"properties.title": "属性:{name}",
|
||||
"recovery.days_ago": "{count} 天前",
|
||||
"recovery.detail": "{file} · {features} 个特征 · 自动保存于 {when}",
|
||||
"recovery.discard_all": "全部放弃",
|
||||
"recovery.discard_all_detail": "此操作无法撤消。",
|
||||
"recovery.discard_all_title": "放弃 {count} 个自动保存?",
|
||||
"recovery.discard_all_title_one": "放弃 1 个自动保存?",
|
||||
"recovery.hours_ago": "{count} 小时前",
|
||||
"recovery.just_now": "刚刚",
|
||||
"recovery.min_ago": "{count} 分钟前",
|
||||
@@ -2917,7 +3297,9 @@
|
||||
"render.output_ready": "已就绪,可渲染",
|
||||
"render.output_run_check": "运行检查",
|
||||
"render.output_size_limit": "{method}:每边最多 {dimension} px,总计 {pixels} 像素。可用的最大尺寸:{width} × {height}。",
|
||||
"render.output_size_method_profile": "要渲染 {width} × {height},请选择 {method} 和“{profile}”CPU 资源配置,或选择更小的尺寸。",
|
||||
"render.output_size_ok": "尺寸正常 · {width} × {height} px",
|
||||
"render.output_size_profile": "要渲染 {width} × {height},请选择“{profile}”CPU 资源配置,或选择更小的尺寸。",
|
||||
"render.output_swap_orientation": "交换宽度和高度",
|
||||
"render.output_tools_inspector": "请在输出检查器中编辑尺寸和格式。",
|
||||
"render.output_view_image": "查看图像",
|
||||
@@ -3130,6 +3512,7 @@
|
||||
"render.size_custom": "自定义…",
|
||||
"render.size_full_hd": "全高清",
|
||||
"render.size_hd": "HD",
|
||||
"render.size_needs_profile": "{size} · 需要“{profile}”",
|
||||
"render.size_presets": "尺寸预设",
|
||||
"render.size_presets_pending": "随输出编辑器推出",
|
||||
"render.size_preview": "预览",
|
||||
@@ -3417,6 +3800,24 @@
|
||||
"sheet.flange_type_contour": "轮廓",
|
||||
"sheet.flange_type_edge": "边线",
|
||||
"sheet.no_body": "没有钣金实体:请使用法兰 > Base 创建,或使用转换为钣金将板材转换为钣金(选择其较大的平面)。",
|
||||
"sheet.personal_rules.confirm_delete": "确认删除",
|
||||
"sheet.personal_rules.delete": "删除",
|
||||
"sheet.personal_rules.delete_prompt": "删除此个人规则?设计中已有的规则不会改变。",
|
||||
"sheet.personal_rules.full": "个人库中已有64条规则。",
|
||||
"sheet.personal_rules.invalid_name": "请输入不含换行符或控制字符的简短名称。",
|
||||
"sheet.personal_rules.invalid_values": "请填写完整的规则值:每个值都必须能在此设计中计算,厚度为正,K 因子在 0 到 1 之间。",
|
||||
"sheet.personal_rules.missing": "所选个人规则已不可用。",
|
||||
"sheet.personal_rules.name": "规则名称",
|
||||
"sheet.personal_rules.name_exists": "同名个人规则已存在,请使用其他名称。",
|
||||
"sheet.personal_rules.name_hint": "唯一名称",
|
||||
"sheet.personal_rules.overwrite": "保存对所选个人规则的修改",
|
||||
"sheet.personal_rules.rename": "重命名",
|
||||
"sheet.personal_rules.rule": "个人规则",
|
||||
"sheet.personal_rules.save": "另存为新规则",
|
||||
"sheet.personal_rules.scope": "保存在您的配置中,适用于所有设计。",
|
||||
"sheet.personal_rules.select": "选择规则",
|
||||
"sheet.personal_rules.title": "个人规则",
|
||||
"sheet.personal_rules.unsupported": "此规则包含当前版本无法使用的值。",
|
||||
"shortcut.json_error": "参数必须采用 JSON 格式:{error}",
|
||||
"shortcut.no_command": "没有命令 `{id}`;JSON 前的文本必须是命令 ID",
|
||||
"shortcut.pin": "固定到 S 框顶部",
|
||||
@@ -3453,8 +3854,10 @@
|
||||
"sketch_text.align_right": "右对齐",
|
||||
"sketch_text.bold": "粗体",
|
||||
"sketch_text.builtin_font": "{family}(内置)",
|
||||
"sketch_text.formula": "以 = 开头即可用参数组成文字:='W' + number(Width)",
|
||||
"sketch_text.italic": "斜体",
|
||||
"sketch_text.loading_fonts": "正在查找已安装字体…",
|
||||
"sketch_text.no_bold": "内置字体没有粗体字形:请选择已安装的字体",
|
||||
"sketch_text.on_path": "文字沿路径排列:由曲线放置",
|
||||
"sketch_text.path_clear": "将文字移离其曲线",
|
||||
"sketch_text.path_hint": "文字所跟随的草图曲线:先单击此处,再选择曲线",
|
||||
@@ -3593,6 +3996,8 @@
|
||||
"ui.3d_mouse_section": "3D 鼠标",
|
||||
"ui.3d_mouse_show_in_view": "在 3D 视图中显示 3D 鼠标",
|
||||
"ui.3d_mouse_show_in_view_tip": "在左下角显示你的 3D 鼠标图示,随你的操作而动。",
|
||||
"ui.3d_mouse_sketch_orbit": "用 3D 鼠标旋转草图",
|
||||
"ui.3d_mouse_sketch_orbit_tip": "草图打开并正对视图时,3D 鼠标也能旋转视图,与鼠标一样。关闭:在你倾斜视图之前,只平移和缩放草图。",
|
||||
"ui.3d_mouse_skip": "我的设备做不到",
|
||||
"ui.3d_mouse_skip_tip": "在两个方向上都跳过这个动作,校准时不包含它。",
|
||||
"ui.3d_mouse_speed": "3D 鼠标速度",
|
||||
@@ -3621,6 +4026,8 @@
|
||||
"ui.3d_mouse_step_twist_counterclockwise": "逆时针扭转摇杆帽,保持住,然后松开。",
|
||||
"ui.3d_mouse_switch_cap": "按回中类型校准",
|
||||
"ui.3d_mouse_switch_trackball": "按轨迹球校准",
|
||||
"ui.3d_mouse_use_direct": "使用直接驱动",
|
||||
"ui.3d_mouse_use_direct_tip": "直接读取 3D 鼠标(hidraw),不经过 spacenavd。",
|
||||
"ui.3d_mouse_view_axis": "视图轴",
|
||||
"ui.3d_mouse_view_off": "关闭",
|
||||
"ui.3d_mouse_view_off_tip": "3D 鼠标驱动程序的配置文件关闭了此轴,因此它的动作不会移动视图。在此选择另一个轴的动作会将两者互换,该动作将不再移动视图。",
|
||||
@@ -3659,6 +4066,7 @@
|
||||
"ui.agent_chat_auth_terminal": "在终端中运行以下命令,然后再次点击连接:",
|
||||
"ui.agent_chat_auth_title": "登录智能体",
|
||||
"ui.agent_chat_cancel": "取消",
|
||||
"ui.agent_chat_cannot_start": "已安装,但无法启动:{error}",
|
||||
"ui.agent_chat_changes": "{n} 项更改,一步撤销",
|
||||
"ui.agent_chat_changes_n": "{n} 项更改",
|
||||
"ui.agent_chat_changes_of": "更改 {n}/{limit}",
|
||||
@@ -3751,9 +4159,12 @@
|
||||
"ui.agent_chat_queued_stopped": "已排队(已停止,未发送)",
|
||||
"ui.agent_chat_refresh": "刷新",
|
||||
"ui.agent_chat_refused": "不允许智能体执行:{reason}",
|
||||
"ui.agent_chat_reinstall": "{agent} 已安装({program}),但 SolidCraft 检查时它没有启动:{error}\n它的安装可能不完整,或是为另一种计算机准备的。请用 `{install}` 重新安装,确认它能在终端中显示版本号,然后点击刷新。",
|
||||
"ui.agent_chat_remove": "从队列中移除",
|
||||
"ui.agent_chat_remove_file": "从这条消息中移除",
|
||||
"ui.agent_chat_remove_imported": "从这条消息中移除;零件仍保留在设计中(撤销可将其删除)",
|
||||
"ui.agent_chat_reply_cut_off": "回复在完成前达到了长度上限,可能不完整。请让智能体继续,或请它回答得更简短。",
|
||||
"ui.agent_chat_reply_declined": "模型拒绝回答这条消息。",
|
||||
"ui.agent_chat_retry": "重试",
|
||||
"ui.agent_chat_right": "右侧",
|
||||
"ui.agent_chat_save": "保存",
|
||||
@@ -3812,12 +4223,17 @@
|
||||
"ui.ai_copy_suffix": "副本",
|
||||
"ui.ai_custom_url": "自定义 URL",
|
||||
"ui.ai_default": "默认",
|
||||
"ui.ai_edit": "编辑",
|
||||
"ui.ai_edit_agent_title": "编辑智能体",
|
||||
"ui.ai_edit_gone": "此智能体已被移除,没有可保存的内容。",
|
||||
"ui.ai_edit_tip": "更改此智能体的名称、命令或端点。已保存的密钥保持隐藏。",
|
||||
"ui.ai_http_busy": "端点繁忙或已达上限,请稍后再试",
|
||||
"ui.ai_http_key": "端点拒绝了密钥:请在“首选项 > AI”中检查",
|
||||
"ui.ai_http_not_found": "找不到该端点或模型:请检查基础 URL 和模型名称",
|
||||
"ui.ai_http_too_large": "对话对此端点来说过大,请开始新的聊天",
|
||||
"ui.ai_key": "API 密钥",
|
||||
"ui.ai_key_hint": "可选;保存在系统钥匙串中",
|
||||
"ui.ai_key_keep_hint": "留空以保留已保存的密钥",
|
||||
"ui.ai_key_needs_https": "密钥只会通过 HTTPS 发送,或发送到本机。",
|
||||
"ui.ai_key_note": "保存在系统钥匙串中,绝不保存在 SolidCraft 的设置里。本地服务器可留空。",
|
||||
"ui.ai_keychain_error": "系统钥匙串拒绝:{error}",
|
||||
@@ -3844,11 +4260,15 @@
|
||||
"ui.ai_permissions": "权限",
|
||||
"ui.ai_preset": "预设",
|
||||
"ui.ai_protocol": "协议",
|
||||
"ui.ai_reasoning_effort": "推理强度",
|
||||
"ui.ai_reasoning_effort_field_hint": "留空 = 服务商默认",
|
||||
"ui.ai_reasoning_effort_hint": "可选。将作为 `reasoning_effort` 发送给端点;各服务商接受的值不同(例如 `low`、`high` 或 `max`)。您在此设置的值绝不会被 SolidCraft 替换。留空则不发送任何内容,沿用服务商默认值。",
|
||||
"ui.ai_remove": "移除",
|
||||
"ui.ai_request_timed_out": "模型用时超过 {seconds} 秒。可在“首选项 › 助手”中调高此端点的请求超时。",
|
||||
"ui.ai_request_timeout": "请求超时",
|
||||
"ui.ai_request_timeout_hint": "对此端点的一次模型请求最多可用的时间,30 秒到 1 小时。本地模型较慢时请调高。",
|
||||
"ui.ai_reset": "重置",
|
||||
"ui.ai_save": "保存",
|
||||
"ui.ai_settings": "AI 设置…",
|
||||
"ui.ai_show_features": "显示 AI 功能",
|
||||
"ui.ai_show_features_note": "智能体聊天:一个面板,由你已在使用的编程智能体或你选择的模型端点处理打开的设计。关闭后:没有 AI 按钮、快捷键、菜单项或面板,也不会查找或启动任何程序。",
|
||||
@@ -3937,6 +4357,7 @@
|
||||
"ui.circle": "圆",
|
||||
"ui.circular_pattern": "圆形阵列",
|
||||
"ui.clear": "清除",
|
||||
"ui.clear_print_face": "清除打印底面",
|
||||
"ui.clear_recent": "清除最近",
|
||||
"ui.clear_the_selection": "清除选择",
|
||||
"ui.click_selects_whole_bodies": "单击选择整个实体",
|
||||
@@ -3971,6 +4392,15 @@
|
||||
"ui.constant": "恒定",
|
||||
"ui.constraints_conflict": "约束冲突",
|
||||
"ui.construction": "构造",
|
||||
"ui.construction.angle_hint": "构造直线:单击一点,然后输入角度或选择方向",
|
||||
"ui.construction.bisector_hint": "角平分线:选择两条相交直线,再选择所需解",
|
||||
"ui.construction.common_hint": "公切线:选择两个圆/圆弧,再选择所需解",
|
||||
"ui.construction.contact_hint": "切线:先选圆/圆弧或开放样条曲线/圆锥曲线,再选接点(自由曲线仅支持端点)",
|
||||
"ui.construction.external_hint": "切线:依次选择圆或圆弧、外部点和所需解",
|
||||
"ui.construction.free_hint": "构造直线:单击两点;右键单击重新开始",
|
||||
"ui.construction.point_hint": "构造直线:单击要经过的点",
|
||||
"ui.construction.reference_hint": "构造直线:先选直线,再选一点;右键单击更换参照",
|
||||
"ui.construction.ribbon_label": "辅助线",
|
||||
"ui.context_menu": "上下文菜单",
|
||||
"ui.continuity_g0": "G0 折痕",
|
||||
"ui.continuity_g1": "G1 相切",
|
||||
@@ -3998,6 +4428,7 @@
|
||||
"ui.dark": "深色",
|
||||
"ui.default_modelling_orientation": "默认建模方向",
|
||||
"ui.delete": "删除",
|
||||
"ui.delete_select_first": "请先选择要删除的内容:特征、实体、组件或草图几何",
|
||||
"ui.depth": "深度",
|
||||
"ui.design": "设计",
|
||||
"ui.design_properties.author": "作者",
|
||||
@@ -4012,6 +4443,40 @@
|
||||
"ui.design_properties.project": "项目",
|
||||
"ui.design_properties.revision": "版本",
|
||||
"ui.design_saved": "已保存到 {path}",
|
||||
"ui.details_access_caption": "面显示刀具能否从所选方向到达它们。",
|
||||
"ui.details_angle": "角度",
|
||||
"ui.details_continuity_caption": "编辑所选接缝。其他接缝保留各自的设置。",
|
||||
"ui.details_continuity_stale": "先前的几何体:请重新运行分析,以编辑此接缝或使其适合视图。",
|
||||
"ui.details_copy_list": "复制列表",
|
||||
"ui.details_curvature": "曲率容差",
|
||||
"ui.details_curvature_caption": "面按其局部曲率半径着色。",
|
||||
"ui.details_direction": "刀具方向",
|
||||
"ui.details_draft_caption": "面按其与脱模方向的夹角着色。",
|
||||
"ui.details_edit_seam": "编辑接缝",
|
||||
"ui.details_fixture": "界面组件示例 — 仅含示例数据",
|
||||
"ui.details_fixture_caption": "使用说明性数值的界面组件示例;这不是模型的分析结果。",
|
||||
"ui.details_fixture_problem": "含问题的检查结果示例",
|
||||
"ui.details_fixture_readout": "测量值示例",
|
||||
"ui.details_flip": "翻转",
|
||||
"ui.details_gap": "间隙",
|
||||
"ui.details_hatch": "为切割面添加剖面线",
|
||||
"ui.details_jump": "曲率突变",
|
||||
"ui.details_key": "图例",
|
||||
"ui.details_offset": "偏移",
|
||||
"ui.details_plane": "平面",
|
||||
"ui.details_pull": "脱模方向",
|
||||
"ui.details_radius": "半径",
|
||||
"ui.details_readout": "读数",
|
||||
"ui.details_samples": "采样数",
|
||||
"ui.details_seam": "{body} · 边 {edge}",
|
||||
"ui.details_settings": "设置",
|
||||
"ui.details_sharp_gap": "尖锐或有间隙",
|
||||
"ui.details_show_all": "显示全部 {count} 项",
|
||||
"ui.details_smooth": "光顺",
|
||||
"ui.details_stripes": "条纹",
|
||||
"ui.details_target": "使几何体适合视图",
|
||||
"ui.details_worst_seams": "连续性最差的接缝",
|
||||
"ui.details_zebra_caption": "反射条纹显示面之间连接的光顺程度。",
|
||||
"ui.diameter": "直径",
|
||||
"ui.dimension": "尺寸",
|
||||
"ui.direct_interaction": "直接交互",
|
||||
@@ -4056,6 +4521,7 @@
|
||||
"ui.edit_in_place_saved_elsewhere": "零件已保存到其他文件;装配体仍链接 {name}",
|
||||
"ui.edit_in_place_wait": "请等待设计中正在运行的操作完成",
|
||||
"ui.edit_section_analysis": "编辑截面分析",
|
||||
"ui.edit_sketch_empty": "没有可编辑的草图",
|
||||
"ui.ellipse": "椭圆",
|
||||
"ui.emboss_wrap_note": "与受支持圆柱相切的正交线轮廓会自动缠绕。选择一个壁以指定目标。",
|
||||
"ui.end_radius": "结束半径",
|
||||
@@ -4066,12 +4532,15 @@
|
||||
"ui.equation_explicit": "显式",
|
||||
"ui.equation_form": "形式",
|
||||
"ui.equation_note": "变量是不带单位的数:sin(t) 按弧度计算。不带单位的结果采用设计的单位。",
|
||||
"ui.equation_note_range": "变量与其范围一样是长度:可与长度参数混用,用于 sin() 时需除以一个长度。没有单位的结果采用设计的单位。",
|
||||
"ui.equation_parametric": "参数式",
|
||||
"ui.equation_variable_unit": "变量使用范围的单位",
|
||||
"ui.equation_x_of_t": "x(t)",
|
||||
"ui.equation_y_of_t": "y(t)",
|
||||
"ui.equation_y_of_x": "y(x)",
|
||||
"ui.equivalent_radius": "等效半径",
|
||||
"ui.expand": "展开",
|
||||
"ui.explode_needs_two_components": "爆炸图会将组件彼此分开,因此设计中需要两个或更多组件(新建组件、插入设计或由实体创建组件)",
|
||||
"ui.exportDxf": "导出 DXF…",
|
||||
"ui.export_ellipsis_keymap": "导出…",
|
||||
"ui.export_keymap_tip": "将按键、S 框收藏和工具栏导出为文件",
|
||||
@@ -4240,12 +4709,14 @@
|
||||
"ui.joints": "关节",
|
||||
"ui.keyboard_shortcuts": "键盘快捷键",
|
||||
"ui.language": "语言",
|
||||
"ui.lasso_select": "套索(徒手圈选:选择完全在圈内的对象)",
|
||||
"ui.layout_compact": "紧凑",
|
||||
"ui.layout_floating": "浮动",
|
||||
"ui.length": "长度",
|
||||
"ui.length_decimals": "长度小数位",
|
||||
"ui.light": "浅色",
|
||||
"ui.line": "直线",
|
||||
"ui.line_arc_hint": "相切圆弧:单击圆弧的终点。再次停留在最后一点可切回直线;右键单击或按 Esc 结束",
|
||||
"ui.link_copies": "链接相同副本",
|
||||
"ui.link_copies_keep": "保留",
|
||||
"ui.link_copies_link": "链接",
|
||||
@@ -4334,6 +4805,7 @@
|
||||
"ui.part_size_shared": "重新生成零件并替换额外添加的特征。此零部件的所有实例都会更新。",
|
||||
"ui.paste": "粘贴",
|
||||
"ui.path": "路径",
|
||||
"ui.pattern_object_type_tip": "实体:在视图或浏览器中选取的实心形状,每个都会被整体复制。\n特征:历史中的步骤,例如拉伸或孔,在历史中或在其生成的面上选取;该步骤会被重复。\n草图两者都不是:请用草图自身的阵列或镜像重复其曲线,或先将其拉伸。",
|
||||
"ui.pattern_on_path": "路径阵列",
|
||||
"ui.perforate_margin_default": "与直径相同",
|
||||
"ui.perforate_pitch": "孔距",
|
||||
@@ -4360,12 +4832,17 @@
|
||||
"ui.plugins_skipped": "有 {count} 个文件夹无法读取。",
|
||||
"ui.plugins_version": "{version}",
|
||||
"ui.point": "点",
|
||||
"ui.point_cloud_add_filter": "添加筛选…",
|
||||
"ui.point_cloud_auto_range": "自动范围",
|
||||
"ui.point_cloud_color_by": "着色方式",
|
||||
"ui.point_cloud_file_colors": "文件颜色",
|
||||
"ui.point_cloud_filter_by": "筛选依据",
|
||||
"ui.point_cloud_height_high": "最高高度",
|
||||
"ui.point_cloud_height_low": "最低高度",
|
||||
"ui.point_cloud_legend_filter": "在上方图例中显示或隐藏",
|
||||
"ui.point_cloud_no_file_colors": "文件中没有颜色",
|
||||
"ui.point_cloud_pause": "暂停",
|
||||
"ui.point_cloud_play": "播放",
|
||||
"ui.point_cloud_single_color": "单色",
|
||||
"ui.point_cloud_size": "点大小",
|
||||
"ui.point_cloud_units": "文件单位",
|
||||
@@ -4374,6 +4851,11 @@
|
||||
"ui.polygon": "多边形",
|
||||
"ui.preferences": "首选项",
|
||||
"ui.press_a_key": "按一个键…",
|
||||
"ui.print_face_cleared": "{body}:已清除打印底面",
|
||||
"ui.print_face_input": "打印底面",
|
||||
"ui.print_face_one_body": "打印底面属于单个实体:请单独发送该实体以更改它",
|
||||
"ui.print_face_pick": "选择实体的一个平面,将其设为打印底面",
|
||||
"ui.print_face_set": "{body}:已设置打印底面;发送到切片软件时实体将放在此面上",
|
||||
"ui.profile": "轮廓",
|
||||
"ui.profile_plane": "轮廓平面",
|
||||
"ui.profiles": "轮廓",
|
||||
@@ -4389,6 +4871,7 @@
|
||||
"ui.properties.inertia_y": "Iyx, Iyy, Iyz",
|
||||
"ui.properties.inertia_z": "Izx, Izy, Izz",
|
||||
"ui.properties.measuring": "正在测量…",
|
||||
"ui.properties.measuring_bodies": "正在测量… 第 {done} 个,共 {total} 个实体",
|
||||
"ui.properties.measuring_failed": "测量在完成前已停止。",
|
||||
"ui.properties.principal_axis": "主轴 {number}",
|
||||
"ui.properties.principal_moments": "主惯性矩",
|
||||
@@ -4437,6 +4920,7 @@
|
||||
"ui.revolve": "旋转",
|
||||
"ui.ribbon_exit": "退出",
|
||||
"ui.ribbon_labels": "显示功能区图标下的文字",
|
||||
"ui.ribbon_menus_skip_pinned": "下拉菜单中不再列出已固定的命令",
|
||||
"ui.ribbon_pin_footer": "固定的命令显示在功能区中。将指针悬停在行上可固定或取消固定。",
|
||||
"ui.ribbon_workspace": "工作区",
|
||||
"ui.right": "右视",
|
||||
@@ -4455,6 +4939,7 @@
|
||||
"ui.selectOther": "选择其他…",
|
||||
"ui.selectTangentChain": "选择相切链",
|
||||
"ui.select_all": "全选",
|
||||
"ui.select_components_by_face": "选择组件(单击面即选择其所属组件)",
|
||||
"ui.selection": "选择",
|
||||
"ui.selection_modifiers": "选择修饰键",
|
||||
"ui.selection_shift_add_only": "Shift+点击仅添加、不取消选择",
|
||||
@@ -4496,6 +4981,11 @@
|
||||
"ui.sketch_intersect_selection_filter": "选择过滤器",
|
||||
"ui.sketch_modifiers": "草图修饰键",
|
||||
"ui.sketch_project_geometry": "几何体",
|
||||
"ui.sketch_report.all_constrained": "全部已完全约束。",
|
||||
"ui.sketch_report.dof": "自由度",
|
||||
"ui.sketch_report.loose": "未完全约束",
|
||||
"ui.sketch_report.status": "状态",
|
||||
"ui.sketch_report.title": "草图报告",
|
||||
"ui.sketch_scale": "草图比例",
|
||||
"ui.sketches": "草图",
|
||||
"ui.slice": "切片",
|
||||
@@ -4600,10 +5090,19 @@
|
||||
"ui.view_centre": "视图中心",
|
||||
"ui.viewport_status_clear": "关闭{name}",
|
||||
"ui.viewport_status_clear_hint": "关闭{name} · Esc",
|
||||
"ui.viewport_status_edges": "{count} 条边",
|
||||
"ui.viewport_status_from": "从 {direction}",
|
||||
"ui.viewport_status_key": "显示{name}的图例",
|
||||
"ui.viewport_status_minimum_radius": "最小半径",
|
||||
"ui.viewport_status_pairs": "{count} 对",
|
||||
"ui.viewport_status_section_hatch": "{setting} · 填充线",
|
||||
"ui.viewport_status_section_plane": "当前平面",
|
||||
"ui.viewport_status_section_tilted": "倾斜 · {offset}",
|
||||
"ui.viewport_status_stripes": "{count} 条条纹",
|
||||
"ui.viewport_status_summary_clear": "全部关闭",
|
||||
"ui.viewport_status_summary_heading": "此视图中",
|
||||
"ui.viewport_status_summary_label": "{name} 和其他 {count} 项",
|
||||
"ui.viewport_status_summary_more": "+{count}",
|
||||
"ui.viewport_theme_follow": "跟随主题",
|
||||
"ui.visual_shaded_hidden_edges": "带隐藏边的着色",
|
||||
"ui.visual_shaded_with_edges": "带边着色",
|
||||
@@ -4640,7 +5139,9 @@
|
||||
"update.button": "更新",
|
||||
"update.button_version": "更新到 {version}",
|
||||
"update.check_automatically": "自动检查更新",
|
||||
"update.check_for_updates": "检查更新",
|
||||
"update.check_now": "立即检查",
|
||||
"update.check_unavailable": "此安装版本无法检查更新。",
|
||||
"update.checking": "正在检查…",
|
||||
"update.copy": "复制",
|
||||
"update.dmg_opened": "磁盘映像已校验并打开:将 SolidCraft 拖到“应用程序”替换旧版本,然后重启 SolidCraft。",
|
||||
|
||||
@@ -20,6 +20,7 @@ struct U {
|
||||
sel: vec4<f32>, // xyz a whole selected body's colour before lighting
|
||||
product_lights_meta: vec4<f32>, // explicit preview flag and bounded count
|
||||
product_lights: array<vec4<f32>,84>, // position/kind, radiance, axis/cone, attenuation
|
||||
sky: vec4<f32>, // xyz = world up; w = 1: shade in linear light with a sky fill (#7974)
|
||||
};
|
||||
|
||||
fn reversed() -> bool {
|
||||
@@ -243,6 +244,44 @@ fn pushed(z: f32) -> f32 {
|
||||
return clamp(z - select(-push, push, reversed()), 0.0, 1.0);
|
||||
}
|
||||
|
||||
/// A far wall seen through the cut where another body's face lying on it was drawn in front of
|
||||
/// it (a shaft in its bore, #9407): its cap colour again, at its depth pulled toward the eye by
|
||||
/// `touch_depth`, so it wins over that face, which is faceted another way.
|
||||
@fragment
|
||||
fn fs_solid_touch(i: TOut, @builtin(front_facing) front: bool) -> CutOut {
|
||||
var o: CutOut;
|
||||
// Derivatives (in `touch_depth`) first, before `solid` may discard.
|
||||
o.depth = touch_depth(i.wp, i.pos.z);
|
||||
o.c = solid(i, front);
|
||||
return o;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_solid_touch_flat(i: FOut, @builtin(front_facing) front: bool) -> CutOut {
|
||||
let t = flat_fragment(i, front);
|
||||
var o: CutOut;
|
||||
o.depth = touch_depth(t.wp, t.pos.z);
|
||||
o.c = solid(t, front);
|
||||
return o;
|
||||
}
|
||||
|
||||
/// The depth of `wp` (depth `z`) pulled toward the eye by what may part two faceted copies of
|
||||
/// one surface: 3 pixels' width along the view ray (display refinement keeps a facet's sag about
|
||||
/// a pixel) and 2 pixels of the face's own depth slope (more where it turns from the eye).
|
||||
fn touch_depth(wp: vec3<f32>, z: f32) -> f32 {
|
||||
let px = min(length(dpdx(wp)), length(dpdy(wp)));
|
||||
let slope = max(abs(dpdx(z)), abs(dpdy(z)));
|
||||
var dir = -u.back.xyz;
|
||||
if (u.eye.w > 0.5) { dir = wp - u.eye.xyz; }
|
||||
let len = length(dir);
|
||||
if (len < 1e-12) { return z; }
|
||||
let c = u.vp * vec4<f32>(wp - dir * (3.0 * px / len), 1.0);
|
||||
if (c.w <= 0.0) { return z; }
|
||||
let pulled = c.z / c.w;
|
||||
if (reversed()) { return clamp(max(pulled, z) + 2.0 * slope, 0.0, 1.0); }
|
||||
return clamp(min(pulled, z) - 2.0 * slope, 0.0, 1.0);
|
||||
}
|
||||
|
||||
/// Depth of the section plane on the view ray through `wp` (a far wall seen through the cut),
|
||||
/// never behind the wall itself (`z`).
|
||||
fn cap_depth(wp: vec3<f32>, z: f32) -> f32 {
|
||||
@@ -385,8 +424,13 @@ fn analysis(i: TOut, k: f32) -> vec4<f32> {
|
||||
let r = reflect(-v, n);
|
||||
var side = cross(v, vec3<f32>(0.0, 0.0, 1.0));
|
||||
if (length(side) < 1e-3) { side = vec3<f32>(1.0, 0.0, 0.0); }
|
||||
let s = sin(dot(r, normalize(side)) * u.ana.y * 3.14159265);
|
||||
let c = select(0.08, 0.95, s > 0.0);
|
||||
let x = dot(r, normalize(side));
|
||||
let s = sin(x * u.ana.y * 3.14159265);
|
||||
// A face whose normal lies in the upright plane through the view (every horizontal
|
||||
// face) reflects straight ahead: its sideways part is zero, on the edge between a black
|
||||
// and a white stripe, and rounding picked one or the other from frame to frame while
|
||||
// the view turned (#2153). Straight ahead is white.
|
||||
let c = select(0.08, 0.95, s > 0.0 || abs(x) < 1e-4);
|
||||
return out_color(vec4<f32>(vec3<f32>(c), 1.0));
|
||||
}
|
||||
if (u.ana.x > 4.5) {
|
||||
@@ -507,6 +551,31 @@ fn lit(i: TOut, visibility: f32) -> vec4<f32> {
|
||||
return lit_color(i, visibility, i.c);
|
||||
}
|
||||
|
||||
/// sRGB to linear light, exact (the straight segment too, which `to_linear` leaves out).
|
||||
fn srgb_decode(c: vec3<f32>) -> vec3<f32> {
|
||||
return select(c / 12.92, pow((c + vec3<f32>(0.055)) / vec3<f32>(1.055), vec3<f32>(2.4)), c > vec3<f32>(0.04045));
|
||||
}
|
||||
|
||||
fn srgb_encode(c: vec3<f32>) -> vec3<f32> {
|
||||
let l = clamp(c, vec3<f32>(0.0), vec3<f32>(1.0));
|
||||
return select(l * 12.92, 1.055 * pow(l, vec3<f32>(1.0 / 2.4)) - vec3<f32>(0.055), l > vec3<f32>(0.0031308));
|
||||
}
|
||||
|
||||
/// The studio light summed in linear light, encoded once (#7974): the key and the eye fill as in
|
||||
/// [`lit_color`], over a sky fill that grows as the face turns up, and the 4% every dielectric
|
||||
/// reflects of that sky (a little more toward grazing), so a near-black face keeps a gradient. The sky
|
||||
/// and the fill are what ambient occlusion (`visibility`) takes away. sRGB out.
|
||||
fn sky_lit(base: vec3<f32>, n: vec3<f32>, diff: f32, fill: f32, visibility: f32) -> vec3<f32> {
|
||||
let up = dot(n, normalize(u.sky.xyz)) * 0.5 + 0.5;
|
||||
let sky = mix(0.18, 0.42, up);
|
||||
// Schlick's rise toward grazing, tempered so mid-tones only gain a soft rim.
|
||||
let fresnel = 0.04 + 0.2 * pow(1.0 - fill, 5.0);
|
||||
let albedo = srgb_decode(base);
|
||||
// Scaled so light and mid-grey faces land near where the sRGB shading puts them.
|
||||
let light = albedo * (0.41 * diff + (0.66 * sky + 0.2 * fill) * visibility) + vec3<f32>(fresnel * sky * visibility);
|
||||
return srgb_encode(light);
|
||||
}
|
||||
|
||||
/// [`lit`] in a colour of its own: a whole highlighted body is lit in its colour lifted by the
|
||||
/// hover amount, or in the selection colour, from the model's own plan triangles.
|
||||
fn lit_color(i: TOut, visibility: f32, base: vec4<f32>) -> vec4<f32> {
|
||||
@@ -533,6 +602,9 @@ fn lit_color(i: TOut, visibility: f32, base: vec4<f32>) -> vec4<f32> {
|
||||
let fill = max(dot(n, v), 0.0);
|
||||
let h = normalize(key + v);
|
||||
let spec = pow(max(dot(n, h), 0.0), 40.0) * 0.25;
|
||||
if u.sky.w > 0.5 {
|
||||
return out_color(vec4<f32>(min(sky_lit(base.rgb, n, diff, fill, visibility) + vec3<f32>(spec), vec3<f32>(1.0)), base.a));
|
||||
}
|
||||
let k = 0.42 + 0.38 * diff + 0.25 * fill - (0.42 + 0.25 * fill) * (1.0 - visibility);
|
||||
return out_color(vec4<f32>(min(base.rgb * k + vec3<f32>(spec), vec3<f32>(1.0)), base.a));
|
||||
}
|
||||
@@ -697,38 +769,96 @@ fn fs_line_all(i: LOut) -> @location(0) vec4<f32> {
|
||||
return out_color(i.c);
|
||||
}
|
||||
|
||||
// Point clouds: each point is a round dot a few pixels across, facing the screen, depth-tested
|
||||
// and written like the model's faces, so the model hides the points behind it and they hide it.
|
||||
// The colour's alpha carries the dot's size (eighths of a pixel).
|
||||
// Point clouds (`view/clouds.rs`): each point is a round dot a few pixels across, facing the
|
||||
// screen, depth-tested and written like the model's faces, so the model hides the points behind
|
||||
// it and they hide it. The cloud's style colours them by their own colour, a ramp or a palette,
|
||||
// and shows only those whose filtered values lie in its ranges or sets.
|
||||
|
||||
struct POut {
|
||||
struct Cloud {
|
||||
style: vec4<f32>, // x: colour (0 own, 1 ramp, 2 palette), y: dot size (px), z, w: ramp range
|
||||
filters: array<vec4<f32>, 4>, // x: kind (0 off, 1 range y…z, 2 whole values y + i for the bits i of w)
|
||||
};
|
||||
@group(1) @binding(3) var<uniform> cloud: Cloud;
|
||||
|
||||
struct CIn {
|
||||
@location(0) p: vec3<f32>,
|
||||
@location(1) v: f32,
|
||||
@location(2) f: vec4<f32>,
|
||||
@location(3) rgb: vec4<f32>,
|
||||
};
|
||||
|
||||
struct COut {
|
||||
@builtin(position) pos: vec4<f32>,
|
||||
@location(0) c: vec4<f32>,
|
||||
@location(1) wp: vec3<f32>,
|
||||
@location(2) at: vec2<f32>,
|
||||
@location(0) wp: vec3<f32>,
|
||||
@location(1) v: f32,
|
||||
@location(2) f: vec4<f32>,
|
||||
@location(3) rgb: vec3<f32>,
|
||||
@location(4) at: vec2<f32>, // the place on its disc
|
||||
@location(5) @interpolate(flat) has: u32,
|
||||
};
|
||||
|
||||
@vertex
|
||||
fn vs_point(@builtin(vertex_index) vi: u32, @location(0) p: vec3<f32>, @location(1) c: vec4<f32>) -> POut {
|
||||
fn vs_cloud_dot(@builtin(vertex_index) vi: u32, i: CIn) -> COut {
|
||||
var xs = array<f32, 6>(-1.0, 1.0, 1.0, -1.0, 1.0, -1.0);
|
||||
var ys = array<f32, 6>(-1.0, -1.0, 1.0, -1.0, 1.0, 1.0);
|
||||
let at = vec2<f32>(xs[vi], ys[vi]);
|
||||
let size = max(c.a * 255.0 / 8.0, 1.0);
|
||||
let centre = u.vp * vec4<f32>(p, 1.0);
|
||||
let half = u.screen.xy * 0.5;
|
||||
var o: POut;
|
||||
o.pos = vec4<f32>(centre.xy + at * size * 0.5 / half * centre.w, centre.z, centre.w);
|
||||
let size = max(cloud.style.y, 1.0);
|
||||
let centre = u.vp * vec4<f32>(i.p, 1.0);
|
||||
var o: COut;
|
||||
o.pos = vec4<f32>(centre.xy + at * size / u.screen.xy * centre.w, centre.z, centre.w);
|
||||
// Behind the eye: nothing.
|
||||
if (near_z(centre) < 0.0) { o.pos = vec4<f32>(0.0, 0.0, 0.0, -1.0); }
|
||||
o.c = vec4<f32>(c.rgb, 1.0);
|
||||
o.wp = p;
|
||||
o.wp = i.p;
|
||||
o.v = i.v;
|
||||
o.f = i.f;
|
||||
o.rgb = i.rgb.rgb;
|
||||
o.has = u32(round(i.rgb.a * 255.0));
|
||||
// Dots under two pixels are squares: a disc that small loses its centre pixel.
|
||||
o.at = at * select(1.0, 0.0, size < 2.0);
|
||||
return o;
|
||||
}
|
||||
|
||||
@fragment
|
||||
fn fs_point(i: POut) -> @location(0) vec4<f32> {
|
||||
if (clipped(i.wp) || dot(i.at, i.at) > 1.0) { discard; }
|
||||
return out_color(i.c);
|
||||
/// Whether filter `f` keeps the value `v`.
|
||||
fn cloud_keeps(f: vec4<f32>, v: f32) -> bool {
|
||||
if (f.x < 0.5) { return true; }
|
||||
if (f.x < 1.5) { return v >= f.y && v <= f.z; }
|
||||
let k = i32(round(v)) - i32(round(f.y));
|
||||
return k >= 0 && k < 32 && ((bitcast<u32>(f.w) >> u32(k)) & 1u) != 0u;
|
||||
}
|
||||
|
||||
fn cloud_ramp(t: f32) -> vec3<f32> {
|
||||
var stops = array<vec3<f32>, 5>(
|
||||
vec3<f32>(40.0, 70.0, 200.0), vec3<f32>(30.0, 170.0, 230.0), vec3<f32>(60.0, 200.0, 90.0),
|
||||
vec3<f32>(240.0, 220.0, 60.0), vec3<f32>(230.0, 70.0, 50.0));
|
||||
let k = clamp(t, 0.0, 1.0) * 4.0;
|
||||
let j = min(u32(k), 3u);
|
||||
return mix(stops[j], stops[j + 1u], k - f32(j)) / 255.0;
|
||||
}
|
||||
|
||||
fn cloud_palette(v: f32) -> vec3<f32> {
|
||||
var colours = array<vec3<f32>, 10>(
|
||||
vec3<f32>(240.0, 140.0, 40.0), vec3<f32>(245.0, 205.0, 65.0), vec3<f32>(230.0, 65.0, 65.0),
|
||||
vec3<f32>(165.0, 75.0, 190.0), vec3<f32>(65.0, 190.0, 115.0), vec3<f32>(75.0, 150.0, 220.0),
|
||||
vec3<f32>(240.0, 120.0, 180.0), vec3<f32>(140.0, 105.0, 75.0), vec3<f32>(120.0, 215.0, 215.0),
|
||||
vec3<f32>(190.0, 190.0, 80.0));
|
||||
if (v < -0.5) { return vec3<f32>(150.0, 160.0, 176.0) / 255.0; }
|
||||
return colours[u32(round(v)) % 10u] / 255.0;
|
||||
}
|
||||
|
||||
|
||||
@fragment
|
||||
fn fs_cloud(o: COut) -> @location(0) vec4<f32> {
|
||||
var out = clipped(o.wp) || dot(o.at, o.at) > 1.0;
|
||||
for (var k = 0u; k < 4u; k++) {
|
||||
out = out || (((o.has >> k) & 1u) != 0u && !cloud_keeps(cloud.filters[k], o.f[k]));
|
||||
}
|
||||
if (out) { discard; }
|
||||
var c = o.rgb;
|
||||
let mode = cloud.style.x;
|
||||
if ((o.has & 16u) != 0u && mode > 1.5) {
|
||||
c = cloud_palette(o.v);
|
||||
} else if ((o.has & 16u) != 0u && mode > 0.5) {
|
||||
c = cloud_ramp((o.v - cloud.style.z) / max(cloud.style.w - cloud.style.z, 1e-12));
|
||||
}
|
||||
return out_color(vec4<f32>(c, 1.0));
|
||||
}
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
{
|
||||
"order": 20,
|
||||
"provenance": "Original SolidCraft mapping of Gruvbox (MIT palette)",
|
||||
"format": "solidcraft-theme/1",
|
||||
"name": "Gruvbox Dark Hard",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"app_bar": "#141617",
|
||||
"toolbar": "#1d2021",
|
||||
"panel": "#1d2021",
|
||||
"panel_header": "#3c3836",
|
||||
"border": "#504945",
|
||||
"text": "#ebdbb2",
|
||||
"text_dim": "#a89984",
|
||||
"accent": "#83a598",
|
||||
"accent_soft": "#414f4b",
|
||||
"sketch_accent": "#a1a322",
|
||||
"error": "#fb4934",
|
||||
"warning": "#fabd2f",
|
||||
"icon": "#d5c4a1",
|
||||
"timeline": "#141617",
|
||||
"hover": "#46403e",
|
||||
"sel_face": "#458588",
|
||||
"sel_edge": "#83a598",
|
||||
"sel_edge_rim": "#aec4bc",
|
||||
"sel_profile": "#076678",
|
||||
"sel_profile_edge": "#458588",
|
||||
"hover_profile": "#83a59830",
|
||||
"hover_profile_edge": "#83a598",
|
||||
"sel_vertex": "#83a598",
|
||||
"origin_plane": "#fe801950",
|
||||
"origin_plane_edge": "#d65d0ec8",
|
||||
"origin_plane_hover": "#83a59896",
|
||||
"origin_point": "#d5c4a1",
|
||||
"axis_x": "#fb4934",
|
||||
"axis_y": "#b8bb26",
|
||||
"axis_z": "#83a598",
|
||||
"construction_plane": "#fe801940",
|
||||
"construction_geom": "#e97926",
|
||||
"body": "#a89984",
|
||||
"body_edge": "#141617",
|
||||
"manipulator": "#83a598",
|
||||
"preview_add": "#83a598",
|
||||
"preview_new": "#fabd2f",
|
||||
"preview_sketch": "#b8bb26",
|
||||
"preview_cut": "#fb49346e",
|
||||
"cube_face": "#ebdbb2",
|
||||
"cube_border": "#665c54",
|
||||
"cube_text": "#282828",
|
||||
"cube_hover": "#83a598",
|
||||
"viewport_top": "#2c2c2c",
|
||||
"viewport_bottom": "#2c2c2c",
|
||||
"grid": "#443f3c",
|
||||
"grid_major": "#504945",
|
||||
"body_selected": "#83a598",
|
||||
"sketch": "#83a598",
|
||||
"sketch_fixed": "#ebdbb2",
|
||||
"sketch_halo": "#141617",
|
||||
"sketch_locked": "#b8bb26",
|
||||
"dimension": "#fabd2f",
|
||||
"dimension_driven": "#b57614",
|
||||
"sketch_point": "#ebdbb2",
|
||||
"sketch_point_free": "#83a598",
|
||||
"dialog_bg": "#3c3836",
|
||||
"dialog_border": "#504945",
|
||||
"chip": "#458588",
|
||||
"section_cap": "#d65d0e",
|
||||
"profile_fill": "#83a59828",
|
||||
"glyph_bg": "#2c2c2c",
|
||||
"glyph_edge": "#fe614c",
|
||||
"glyph_text": "#fe614c",
|
||||
"overlay": "#1d2021f0",
|
||||
"rubber_band": "#83a598",
|
||||
"app_bar_text": "#ebdbb2",
|
||||
"app_bar_hover": "#ebdbb21c",
|
||||
"timeline_item": "#3c3836",
|
||||
"timeline_item_error": "#63221f",
|
||||
"timeline_marker": "#bdae93",
|
||||
"field": "#141617",
|
||||
"box_window": "#83a598",
|
||||
"box_crossing": "#b8bb26",
|
||||
"sketch_projected": "#d3869b",
|
||||
"sketch_lost": "#fb4934",
|
||||
"sketch_construction": "#fe8019",
|
||||
"sketch_centerline": "#d65d0e",
|
||||
"bend_up": "#b8bb26",
|
||||
"bend_down": "#fe8019",
|
||||
"interference": "#fb4934",
|
||||
"icons.agent": "#d3869b",
|
||||
"surface_fill": "#fe9755",
|
||||
"surface_soft": "#382c20",
|
||||
"surface_ink": "#fe8019",
|
||||
"surface_accent": "#e97926",
|
||||
"mesh_fill": "#e1ab32",
|
||||
"mesh_soft": "#383323",
|
||||
"mesh_ink": "#fabd2f",
|
||||
"mesh_accent": "#c39429",
|
||||
"form_fill": "#ea9bb0",
|
||||
"form_soft": "#332c30",
|
||||
"form_tab_ink": "#d3869b",
|
||||
"form_accent": "#cf8297",
|
||||
"sheet_fill": "#93c681",
|
||||
"sheet_soft": "#2b332c",
|
||||
"sheet_ink": "#8ec07c",
|
||||
"render_fill": "#fc9483",
|
||||
"render_soft": "#382523",
|
||||
"render_ink": "#fb5d4a",
|
||||
"render_accent": "#fe614c",
|
||||
"sketch_soft": "#303322",
|
||||
"sketch_ink": "#b8bb26",
|
||||
"form_ink": "#ebdbb2",
|
||||
"form_dim": "#bdae93",
|
||||
"form_primary": "#83a598",
|
||||
"form_error": "#fb4934",
|
||||
"form_error_fill": "#63221f",
|
||||
"form_success": "#b8bb26",
|
||||
"form_success_fill": "#343a28",
|
||||
"dialog_body": "#1d2021",
|
||||
"dialog_footer": "#3c3836",
|
||||
"dialog_rule": "#504945",
|
||||
"control_fill": "#141617",
|
||||
"control_border": "#7c6f64",
|
||||
"dialog_label": "#ebdbb2",
|
||||
"selected_ink": "#ebdbb2",
|
||||
"selected_bg": "#414f4b",
|
||||
"on_accent": "#1d2021"
|
||||
},
|
||||
"icon_palette": {
|
||||
"ink": "#141617",
|
||||
"line": "#d5c4a1",
|
||||
"passive-1": "#c5c0b8",
|
||||
"passive-2": "#9a948d",
|
||||
"passive-3": "#706b64",
|
||||
"guide": "#a89984",
|
||||
"solid": [
|
||||
"#b8dbcd",
|
||||
"#9bbeb1",
|
||||
"#83a598"
|
||||
],
|
||||
"surface": [
|
||||
"#fcc4a3",
|
||||
"#fe9755",
|
||||
"#e97926"
|
||||
],
|
||||
"mesh": [
|
||||
"#fbca67",
|
||||
"#e1ab32",
|
||||
"#c39429"
|
||||
],
|
||||
"form": [
|
||||
"#fbbfce",
|
||||
"#ea9bb0",
|
||||
"#cf8297"
|
||||
],
|
||||
"sketch": [
|
||||
"#d7db50",
|
||||
"#babd2a",
|
||||
"#a1a322"
|
||||
],
|
||||
"constraint": [
|
||||
"#fcc2b7",
|
||||
"#fc9483",
|
||||
"#fe614c"
|
||||
],
|
||||
"construction": [
|
||||
"#fcc4a3",
|
||||
"#fe9755",
|
||||
"#e97926"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
{
|
||||
"order": 30,
|
||||
"provenance": "Original SolidCraft mapping of Gruvbox (MIT palette)",
|
||||
"format": "solidcraft-theme/1",
|
||||
"name": "Gruvbox Dark Soft",
|
||||
"base": "dark",
|
||||
"colors": {
|
||||
"app_bar": "#1d2021",
|
||||
"toolbar": "#32302f",
|
||||
"panel": "#32302f",
|
||||
"panel_header": "#3c3836",
|
||||
"border": "#504945",
|
||||
"text": "#ebdbb2",
|
||||
"text_dim": "#a89984",
|
||||
"accent": "#83a598",
|
||||
"accent_soft": "#4e5954",
|
||||
"selected_ink": "#ebdbb2",
|
||||
"sketch_accent": "#a1a322",
|
||||
"error": "#fb4934",
|
||||
"warning": "#fabd2f",
|
||||
"icon": "#d5c4a1",
|
||||
"timeline": "#1d2021",
|
||||
"hover": "#46403e",
|
||||
"sel_face": "#458588",
|
||||
"sel_edge": "#83a598",
|
||||
"sel_edge_rim": "#aec4bc",
|
||||
"sel_profile": "#076678",
|
||||
"sel_profile_edge": "#458588",
|
||||
"hover_profile": "#83a59830",
|
||||
"hover_profile_edge": "#83a598",
|
||||
"sel_vertex": "#83a598",
|
||||
"origin_plane": "#fe801950",
|
||||
"origin_plane_edge": "#d65d0ec8",
|
||||
"origin_plane_hover": "#83a59896",
|
||||
"origin_point": "#d5c4a1",
|
||||
"axis_x": "#fb4934",
|
||||
"axis_y": "#b8bb26",
|
||||
"axis_z": "#83a598",
|
||||
"construction_plane": "#fe801940",
|
||||
"construction_geom": "#e97926",
|
||||
"body": "#a89984",
|
||||
"body_edge": "#1d2021",
|
||||
"manipulator": "#83a598",
|
||||
"preview_add": "#83a598",
|
||||
"preview_new": "#fabd2f",
|
||||
"preview_sketch": "#b8bb26",
|
||||
"preview_cut": "#fb49346e",
|
||||
"cube_face": "#ebdbb2",
|
||||
"cube_border": "#665c54",
|
||||
"cube_text": "#282828",
|
||||
"cube_hover": "#83a598",
|
||||
"viewport_top": "#373432",
|
||||
"viewport_bottom": "#373432",
|
||||
"grid": "#443f3c",
|
||||
"grid_major": "#504945",
|
||||
"body_selected": "#83a598",
|
||||
"sketch": "#83a598",
|
||||
"sketch_fixed": "#ebdbb2",
|
||||
"sketch_halo": "#1d2021",
|
||||
"sketch_locked": "#b8bb26",
|
||||
"dimension": "#fabd2f",
|
||||
"dimension_driven": "#b57614",
|
||||
"sketch_point": "#ebdbb2",
|
||||
"sketch_point_free": "#83a598",
|
||||
"dialog_bg": "#3c3836",
|
||||
"dialog_border": "#504945",
|
||||
"chip": "#458588",
|
||||
"section_cap": "#d65d0e",
|
||||
"profile_fill": "#83a59828",
|
||||
"glyph_bg": "#373432",
|
||||
"glyph_edge": "#fe614c",
|
||||
"glyph_text": "#fe614c",
|
||||
"overlay": "#32302ff0",
|
||||
"rubber_band": "#83a598",
|
||||
"app_bar_text": "#ebdbb2",
|
||||
"app_bar_hover": "#ebdbb21c",
|
||||
"timeline_item": "#3c3836",
|
||||
"timeline_item_error": "#702b28",
|
||||
"timeline_marker": "#bdae93",
|
||||
"field": "#1d2021",
|
||||
"box_window": "#83a598",
|
||||
"box_crossing": "#b8bb26",
|
||||
"sketch_projected": "#d3869b",
|
||||
"sketch_lost": "#fb4934",
|
||||
"sketch_construction": "#fe8019",
|
||||
"sketch_centerline": "#d65d0e",
|
||||
"bend_up": "#b8bb26",
|
||||
"bend_down": "#fe8019",
|
||||
"interference": "#fb4934",
|
||||
"icons.agent": "#d3869b",
|
||||
"surface_fill": "#fe9755",
|
||||
"surface_soft": "#4a3a2c",
|
||||
"surface_ink": "#fe8b2e",
|
||||
"surface_accent": "#e97926",
|
||||
"mesh_fill": "#e1ab32",
|
||||
"mesh_soft": "#4a412f",
|
||||
"mesh_ink": "#fabd2f",
|
||||
"mesh_accent": "#c39429",
|
||||
"form_fill": "#ea9bb0",
|
||||
"form_soft": "#453a3c",
|
||||
"form_tab_ink": "#d996a8",
|
||||
"form_accent": "#cf8297",
|
||||
"sheet_fill": "#93c681",
|
||||
"sheet_soft": "#3d4138",
|
||||
"sheet_ink": "#8ec07c",
|
||||
"render_fill": "#fc9483",
|
||||
"render_soft": "#4a3330",
|
||||
"render_ink": "#fc7e6f",
|
||||
"render_accent": "#fe614c",
|
||||
"sketch_soft": "#42412e",
|
||||
"sketch_ink": "#b8bb26",
|
||||
"form_ink": "#ebdbb2",
|
||||
"form_dim": "#bdae93",
|
||||
"form_primary": "#83a598",
|
||||
"form_error": "#fb4934",
|
||||
"form_error_fill": "#702b28",
|
||||
"form_success": "#b8bb26",
|
||||
"form_success_fill": "#343a28",
|
||||
"dialog_body": "#32302f",
|
||||
"dialog_footer": "#3c3836",
|
||||
"dialog_rule": "#504945",
|
||||
"control_fill": "#1d2021",
|
||||
"control_border": "#7c6f64",
|
||||
"dialog_label": "#ebdbb2",
|
||||
"selected_ink": "#ebdbb2",
|
||||
"selected_bg": "#4e5954",
|
||||
"on_accent": "#1d2021"
|
||||
},
|
||||
"icon_palette": {
|
||||
"ink": "#1d2021",
|
||||
"line": "#d5c4a1",
|
||||
"passive-1": "#c5c0b8",
|
||||
"passive-2": "#9a948d",
|
||||
"passive-3": "#706b64",
|
||||
"guide": "#a89984",
|
||||
"solid": [
|
||||
"#b8dbcd",
|
||||
"#9bbeb1",
|
||||
"#83a598"
|
||||
],
|
||||
"surface": [
|
||||
"#fcc4a3",
|
||||
"#fe9755",
|
||||
"#e97926"
|
||||
],
|
||||
"mesh": [
|
||||
"#fbca67",
|
||||
"#e1ab32",
|
||||
"#c39429"
|
||||
],
|
||||
"form": [
|
||||
"#fbbfce",
|
||||
"#ea9bb0",
|
||||
"#cf8297"
|
||||
],
|
||||
"sketch": [
|
||||
"#d7db50",
|
||||
"#babd2a",
|
||||
"#a1a322"
|
||||
],
|
||||
"constraint": [
|
||||
"#fcc2b7",
|
||||
"#fc9483",
|
||||
"#fe614c"
|
||||
],
|
||||
"construction": [
|
||||
"#fcc4a3",
|
||||
"#fe9755",
|
||||
"#e97926"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -122,7 +122,6 @@
|
||||
"control_fill": "#1d2021",
|
||||
"control_border": "#7c6f64",
|
||||
"dialog_label": "#ebdbb2",
|
||||
"selected_ink": "#ebdbb2",
|
||||
"selected_bg": "#48544f",
|
||||
"on_accent": "#1d2021"
|
||||
},
|
||||
@@ -168,5 +167,124 @@
|
||||
"#fe9755",
|
||||
"#e97926"
|
||||
]
|
||||
}
|
||||
},
|
||||
"options": [
|
||||
{
|
||||
"id": "contrast",
|
||||
"type": "choice",
|
||||
"default": "standard",
|
||||
"label": {
|
||||
"de": "Kontrast",
|
||||
"en": "Contrast",
|
||||
"ja": "コントラスト",
|
||||
"ko": "대비",
|
||||
"zh": "对比度"
|
||||
},
|
||||
"help": {
|
||||
"de": "Wähle die weiche, normale oder harte Gruvbox-Palette.",
|
||||
"en": "Choose the soft, standard or hard Gruvbox palette.",
|
||||
"ja": "Gruvboxのソフト・標準・ハードのパレットを選びます。",
|
||||
"ko": "Gruvbox의 부드러운, 표준 또는 강한 팔레트를 선택합니다.",
|
||||
"zh": "选择柔和、标准或强对比的 Gruvbox 配色。"
|
||||
},
|
||||
"values": [
|
||||
{
|
||||
"id": "soft",
|
||||
"label": {
|
||||
"de": "Weich",
|
||||
"en": "Soft",
|
||||
"ja": "ソフト",
|
||||
"ko": "부드럽게",
|
||||
"zh": "柔和"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "standard",
|
||||
"label": {
|
||||
"de": "Standard",
|
||||
"en": "Standard",
|
||||
"ja": "標準",
|
||||
"ko": "표준",
|
||||
"zh": "标准"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "hard",
|
||||
"label": {
|
||||
"de": "Hart",
|
||||
"en": "Hard",
|
||||
"ja": "ハード",
|
||||
"ko": "강하게",
|
||||
"zh": "强对比"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"overlays": [
|
||||
{
|
||||
"when": {
|
||||
"opt": "contrast",
|
||||
"eq": "soft"
|
||||
},
|
||||
"colors": {
|
||||
"toolbar": "#32302f",
|
||||
"panel": "#32302f",
|
||||
"accent_soft": "#4e5954",
|
||||
"viewport_top": "#373432",
|
||||
"viewport_bottom": "#373432",
|
||||
"glyph_bg": "#373432",
|
||||
"overlay": "#32302ff0",
|
||||
"timeline_item_error": "#702b28",
|
||||
"surface_soft": "#4a3a2c",
|
||||
"surface_ink": "#fe8b2e",
|
||||
"mesh_soft": "#4a412f",
|
||||
"form_soft": "#453a3c",
|
||||
"form_tab_ink": "#d996a8",
|
||||
"sheet_soft": "#3d4138",
|
||||
"render_soft": "#4a3330",
|
||||
"render_ink": "#fc7e6f",
|
||||
"sketch_soft": "#42412e",
|
||||
"form_error_fill": "#702b28",
|
||||
"dialog_body": "#32302f",
|
||||
"selected_bg": "#4e5954"
|
||||
}
|
||||
},
|
||||
{
|
||||
"when": {
|
||||
"opt": "contrast",
|
||||
"eq": "hard"
|
||||
},
|
||||
"colors": {
|
||||
"app_bar": "#141617",
|
||||
"toolbar": "#1d2021",
|
||||
"panel": "#1d2021",
|
||||
"accent_soft": "#414f4b",
|
||||
"timeline": "#141617",
|
||||
"body_edge": "#141617",
|
||||
"viewport_top": "#2c2c2c",
|
||||
"viewport_bottom": "#2c2c2c",
|
||||
"sketch_halo": "#141617",
|
||||
"glyph_bg": "#2c2c2c",
|
||||
"overlay": "#1d2021f0",
|
||||
"timeline_item_error": "#63221f",
|
||||
"field": "#141617",
|
||||
"surface_soft": "#382c20",
|
||||
"mesh_soft": "#383323",
|
||||
"form_soft": "#332c30",
|
||||
"form_tab_ink": "#d3869b",
|
||||
"sheet_soft": "#2b332c",
|
||||
"render_soft": "#382523",
|
||||
"render_ink": "#fb5d4a",
|
||||
"sketch_soft": "#303322",
|
||||
"form_error_fill": "#63221f",
|
||||
"dialog_body": "#1d2021",
|
||||
"control_fill": "#141617",
|
||||
"selected_bg": "#414f4b"
|
||||
},
|
||||
"icon_palette": {
|
||||
"ink": "#141617"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
{
|
||||
"order": 50,
|
||||
"provenance": "Original SolidCraft mapping of Gruvbox (MIT palette)",
|
||||
"format": "solidcraft-theme/1",
|
||||
"name": "Gruvbox Light Hard",
|
||||
"base": "light",
|
||||
"colors": {
|
||||
"app_bar": "#3c3836",
|
||||
"toolbar": "#f9f5d7",
|
||||
"panel": "#f9f5d7",
|
||||
"panel_header": "#ebdbb2",
|
||||
"border": "#d5c4a1",
|
||||
"text": "#3c3836",
|
||||
"text_dim": "#7c6f64",
|
||||
"accent": "#076678",
|
||||
"accent_soft": "#c9d8c4",
|
||||
"sketch_accent": "#625e15",
|
||||
"error": "#9d0006",
|
||||
"warning": "#b57614",
|
||||
"icon": "#504945",
|
||||
"timeline": "#ebdbb2",
|
||||
"hover": "#f1e5c1",
|
||||
"sel_face": "#458588",
|
||||
"sel_edge": "#076678",
|
||||
"sel_edge_rim": "#83a598",
|
||||
"sel_profile": "#076678",
|
||||
"sel_profile_edge": "#458588",
|
||||
"hover_profile": "#45858830",
|
||||
"hover_profile_edge": "#458588",
|
||||
"sel_vertex": "#076678",
|
||||
"origin_plane": "#fe80195e",
|
||||
"origin_plane_edge": "#d65d0ec8",
|
||||
"origin_plane_hover": "#45858896",
|
||||
"origin_point": "#d5c4a1",
|
||||
"axis_x": "#cc241d",
|
||||
"axis_y": "#98971a",
|
||||
"axis_z": "#458588",
|
||||
"construction_plane": "#fe801946",
|
||||
"construction_geom": "#9b3407",
|
||||
"body": "#bdae93",
|
||||
"body_edge": "#3c3836",
|
||||
"manipulator": "#076678",
|
||||
"preview_add": "#458588",
|
||||
"preview_new": "#d79921",
|
||||
"preview_sketch": "#98971a",
|
||||
"preview_cut": "#cc241d6e",
|
||||
"cube_face": "#fbf1c7",
|
||||
"cube_border": "#7c6f64",
|
||||
"cube_text": "#3c3836",
|
||||
"cube_hover": "#83a598",
|
||||
"viewport_top": "#fbf8e3",
|
||||
"viewport_bottom": "#ebdbb2",
|
||||
"grid": "#d5c4a1",
|
||||
"grid_major": "#bdae93",
|
||||
"body_selected": "#83a598",
|
||||
"sketch": "#076678",
|
||||
"sketch_fixed": "#282828",
|
||||
"sketch_halo": "#fbf8e3",
|
||||
"sketch_locked": "#79740e",
|
||||
"dimension": "#1f5c40",
|
||||
"dimension_driven": "#4f7d64",
|
||||
"sketch_point": "#282828",
|
||||
"sketch_point_free": "#076678",
|
||||
"dialog_bg": "#f9f5d7",
|
||||
"dialog_border": "#d5c4a1",
|
||||
"chip": "#458588",
|
||||
"section_cap": "#d65d0e",
|
||||
"profile_fill": "#fabd2f46",
|
||||
"glyph_bg": "#fcfaeb",
|
||||
"glyph_edge": "#a91714",
|
||||
"glyph_text": "#a91714",
|
||||
"overlay": "#f9f5d7eb",
|
||||
"rubber_band": "#076678",
|
||||
"app_bar_text": "#fbf1c7",
|
||||
"app_bar_hover": "#fbf1c71c",
|
||||
"timeline_item": "#f9f5d7",
|
||||
"timeline_item_error": "#f0cbb2",
|
||||
"timeline_marker": "#504945",
|
||||
"field": "#fcfaeb",
|
||||
"box_window": "#076678",
|
||||
"box_crossing": "#79740e",
|
||||
"sketch_projected": "#8f3f71",
|
||||
"sketch_lost": "#9d0006",
|
||||
"sketch_construction": "#af3a03",
|
||||
"sketch_centerline": "#d65d0e",
|
||||
"bend_up": "#79740e",
|
||||
"bend_down": "#af3a03",
|
||||
"interference": "#cc241d",
|
||||
"icons.agent": "#8f3f71",
|
||||
"surface_fill": "#df663c",
|
||||
"surface_soft": "#f3e6c6",
|
||||
"surface_ink": "#af3a03",
|
||||
"surface_accent": "#9b3407",
|
||||
"mesh_fill": "#c08024",
|
||||
"mesh_soft": "#f4ebc7",
|
||||
"mesh_ink": "#915e10",
|
||||
"mesh_accent": "#7b5112",
|
||||
"form_fill": "#c46fa2",
|
||||
"form_soft": "#f1e6cf",
|
||||
"form_tab_ink": "#8f3f71",
|
||||
"form_accent": "#893a6c",
|
||||
"sheet_fill": "#659f7a",
|
||||
"sheet_soft": "#eaebcd",
|
||||
"sheet_ink": "#3d7252",
|
||||
"render_fill": "#e85a4d",
|
||||
"render_soft": "#f2e1c6",
|
||||
"render_ink": "#9d0006",
|
||||
"render_accent": "#a91714",
|
||||
"sketch_soft": "#efebc7",
|
||||
"sketch_ink": "#6e6a0d",
|
||||
"form_ink": "#3c3836",
|
||||
"form_dim": "#665c54",
|
||||
"form_primary": "#076678",
|
||||
"form_error": "#9d0006",
|
||||
"form_error_fill": "#f0cbb2",
|
||||
"form_success": "#427b58",
|
||||
"form_success_fill": "#dae3b6",
|
||||
"dialog_body": "#f9f5d7",
|
||||
"dialog_footer": "#ebdbb2",
|
||||
"dialog_rule": "#d5c4a1",
|
||||
"control_fill": "#fcfaeb",
|
||||
"control_border": "#a89984",
|
||||
"dialog_label": "#3c3836",
|
||||
"selected_ink": "#3c3836",
|
||||
"selected_bg": "#c9d8c4",
|
||||
"on_accent": "#fbf1c7"
|
||||
},
|
||||
"icon_palette": {
|
||||
"ink": "#3c3836",
|
||||
"line": "#504945",
|
||||
"passive-1": "#e9e3df",
|
||||
"passive-2": "#b8b3af",
|
||||
"passive-3": "#8a8581",
|
||||
"guide": "#7c6f64",
|
||||
"solid": [
|
||||
"#87d5e9",
|
||||
"#4e9caf",
|
||||
"#076678"
|
||||
],
|
||||
"surface": [
|
||||
"#feb299",
|
||||
"#df663c",
|
||||
"#9b3407"
|
||||
],
|
||||
"mesh": [
|
||||
"#fcb864",
|
||||
"#c08024",
|
||||
"#7b5112"
|
||||
],
|
||||
"form": [
|
||||
"#fbaad9",
|
||||
"#c46fa2",
|
||||
"#893a6c"
|
||||
],
|
||||
"sketch": [
|
||||
"#d0cc73",
|
||||
"#989439",
|
||||
"#625e15"
|
||||
],
|
||||
"constraint": [
|
||||
"#fab3a8",
|
||||
"#e85a4d",
|
||||
"#a91714"
|
||||
],
|
||||
"construction": [
|
||||
"#feb299",
|
||||
"#df663c",
|
||||
"#9b3407"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
{
|
||||
"order": 60,
|
||||
"provenance": "Original SolidCraft mapping of Gruvbox (MIT palette)",
|
||||
"format": "solidcraft-theme/1",
|
||||
"name": "Gruvbox Light Soft",
|
||||
"base": "light",
|
||||
"colors": {
|
||||
"app_bar": "#3c3836",
|
||||
"toolbar": "#f2e5bc",
|
||||
"panel": "#f2e5bc",
|
||||
"panel_header": "#ebdbb2",
|
||||
"border": "#d5c4a1",
|
||||
"text": "#3c3836",
|
||||
"text_dim": "#7c6f64",
|
||||
"accent": "#076678",
|
||||
"accent_soft": "#c3ccae",
|
||||
"sketch_accent": "#625e15",
|
||||
"error": "#9d0006",
|
||||
"warning": "#b57614",
|
||||
"icon": "#504945",
|
||||
"timeline": "#ebdbb2",
|
||||
"hover": "#eedfb6",
|
||||
"sel_face": "#458588",
|
||||
"sel_edge": "#076678",
|
||||
"sel_edge_rim": "#83a598",
|
||||
"sel_profile": "#076678",
|
||||
"sel_profile_edge": "#458588",
|
||||
"hover_profile": "#45858830",
|
||||
"hover_profile_edge": "#458588",
|
||||
"sel_vertex": "#076678",
|
||||
"origin_plane": "#fe80195e",
|
||||
"origin_plane_edge": "#d65d0ec8",
|
||||
"origin_plane_hover": "#45858896",
|
||||
"origin_point": "#d5c4a1",
|
||||
"axis_x": "#cc241d",
|
||||
"axis_y": "#98971a",
|
||||
"axis_z": "#458588",
|
||||
"construction_plane": "#fe801946",
|
||||
"construction_geom": "#9b3407",
|
||||
"body": "#bdae93",
|
||||
"body_edge": "#3c3836",
|
||||
"manipulator": "#076678",
|
||||
"preview_add": "#458588",
|
||||
"preview_new": "#d79921",
|
||||
"preview_sketch": "#98971a",
|
||||
"preview_cut": "#cc241d6e",
|
||||
"cube_face": "#fbf1c7",
|
||||
"cube_border": "#7c6f64",
|
||||
"cube_text": "#3c3836",
|
||||
"cube_hover": "#83a598",
|
||||
"viewport_top": "#f6edd0",
|
||||
"viewport_bottom": "#ebdbb2",
|
||||
"grid": "#d5c4a1",
|
||||
"grid_major": "#bdae93",
|
||||
"body_selected": "#83a598",
|
||||
"sketch": "#076678",
|
||||
"sketch_fixed": "#282828",
|
||||
"sketch_halo": "#f6edd0",
|
||||
"sketch_locked": "#79740e",
|
||||
"dimension": "#1f5c40",
|
||||
"dimension_driven": "#4f7d64",
|
||||
"sketch_point": "#282828",
|
||||
"sketch_point_free": "#076678",
|
||||
"dialog_bg": "#f2e5bc",
|
||||
"dialog_border": "#d5c4a1",
|
||||
"chip": "#458588",
|
||||
"section_cap": "#d65d0e",
|
||||
"profile_fill": "#fabd2f46",
|
||||
"glyph_bg": "#f8f2de",
|
||||
"glyph_edge": "#a91714",
|
||||
"glyph_text": "#a91714",
|
||||
"overlay": "#f2e5bceb",
|
||||
"rubber_band": "#076678",
|
||||
"app_bar_text": "#fbf1c7",
|
||||
"app_bar_hover": "#fbf1c71c",
|
||||
"timeline_item": "#f2e5bc",
|
||||
"timeline_item_error": "#eabe9c",
|
||||
"timeline_marker": "#504945",
|
||||
"field": "#f8f2de",
|
||||
"box_window": "#076678",
|
||||
"box_crossing": "#79740e",
|
||||
"sketch_projected": "#8f3f71",
|
||||
"sketch_lost": "#9d0006",
|
||||
"sketch_construction": "#af3a03",
|
||||
"sketch_centerline": "#d65d0e",
|
||||
"bend_up": "#79740e",
|
||||
"bend_down": "#af3a03",
|
||||
"interference": "#cc241d",
|
||||
"icons.agent": "#8f3f71",
|
||||
"surface_fill": "#df663c",
|
||||
"surface_soft": "#edd7ad",
|
||||
"surface_ink": "#a83803",
|
||||
"surface_accent": "#9b3407",
|
||||
"mesh_fill": "#c08024",
|
||||
"mesh_soft": "#eddcaf",
|
||||
"mesh_ink": "#84560f",
|
||||
"mesh_accent": "#7b5112",
|
||||
"form_fill": "#c46fa2",
|
||||
"form_soft": "#ead8b6",
|
||||
"form_tab_ink": "#8f3f71",
|
||||
"form_accent": "#893a6c",
|
||||
"sheet_fill": "#659f7a",
|
||||
"sheet_soft": "#e4ddb4",
|
||||
"sheet_ink": "#38694b",
|
||||
"render_fill": "#e85a4d",
|
||||
"render_soft": "#ebd3ad",
|
||||
"render_ink": "#9d0006",
|
||||
"render_accent": "#a91714",
|
||||
"sketch_soft": "#e8dcae",
|
||||
"sketch_ink": "#66610c",
|
||||
"form_ink": "#3c3836",
|
||||
"form_dim": "#665c54",
|
||||
"form_primary": "#076678",
|
||||
"form_error": "#9d0006",
|
||||
"form_error_fill": "#eabe9c",
|
||||
"form_success": "#427b58",
|
||||
"form_success_fill": "#dae3b6",
|
||||
"dialog_body": "#f2e5bc",
|
||||
"dialog_footer": "#ebdbb2",
|
||||
"dialog_rule": "#d5c4a1",
|
||||
"control_fill": "#f8f2de",
|
||||
"control_border": "#a89984",
|
||||
"dialog_label": "#3c3836",
|
||||
"selected_ink": "#3c3836",
|
||||
"selected_bg": "#c3ccae",
|
||||
"on_accent": "#fbf1c7"
|
||||
},
|
||||
"icon_palette": {
|
||||
"ink": "#3c3836",
|
||||
"line": "#504945",
|
||||
"passive-1": "#e9e3df",
|
||||
"passive-2": "#b8b3af",
|
||||
"passive-3": "#8a8581",
|
||||
"guide": "#7c6f64",
|
||||
"solid": [
|
||||
"#87d5e9",
|
||||
"#4e9caf",
|
||||
"#076678"
|
||||
],
|
||||
"surface": [
|
||||
"#feb299",
|
||||
"#df663c",
|
||||
"#9b3407"
|
||||
],
|
||||
"mesh": [
|
||||
"#fcb864",
|
||||
"#c08024",
|
||||
"#7b5112"
|
||||
],
|
||||
"form": [
|
||||
"#fbaad9",
|
||||
"#c46fa2",
|
||||
"#893a6c"
|
||||
],
|
||||
"sketch": [
|
||||
"#d0cc73",
|
||||
"#989439",
|
||||
"#625e15"
|
||||
],
|
||||
"constraint": [
|
||||
"#fab3a8",
|
||||
"#e85a4d",
|
||||
"#a91714"
|
||||
],
|
||||
"construction": [
|
||||
"#feb299",
|
||||
"#df663c",
|
||||
"#9b3407"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -167,5 +167,127 @@
|
||||
"#df663c",
|
||||
"#9b3407"
|
||||
]
|
||||
}
|
||||
},
|
||||
"options": [
|
||||
{
|
||||
"id": "contrast",
|
||||
"type": "choice",
|
||||
"default": "standard",
|
||||
"label": {
|
||||
"de": "Kontrast",
|
||||
"en": "Contrast",
|
||||
"ja": "コントラスト",
|
||||
"ko": "대비",
|
||||
"zh": "对比度"
|
||||
},
|
||||
"help": {
|
||||
"de": "Wähle die weiche, normale oder harte Gruvbox-Palette.",
|
||||
"en": "Choose the soft, standard or hard Gruvbox palette.",
|
||||
"ja": "Gruvboxのソフト・標準・ハードのパレットを選びます。",
|
||||
"ko": "Gruvbox의 부드러운, 표준 또는 강한 팔레트를 선택합니다.",
|
||||
"zh": "选择柔和、标准或强对比的 Gruvbox 配色。"
|
||||
},
|
||||
"values": [
|
||||
{
|
||||
"id": "soft",
|
||||
"label": {
|
||||
"de": "Weich",
|
||||
"en": "Soft",
|
||||
"ja": "ソフト",
|
||||
"ko": "부드럽게",
|
||||
"zh": "柔和"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "standard",
|
||||
"label": {
|
||||
"de": "Standard",
|
||||
"en": "Standard",
|
||||
"ja": "標準",
|
||||
"ko": "표준",
|
||||
"zh": "标准"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "hard",
|
||||
"label": {
|
||||
"de": "Hart",
|
||||
"en": "Hard",
|
||||
"ja": "ハード",
|
||||
"ko": "강하게",
|
||||
"zh": "强对比"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"overlays": [
|
||||
{
|
||||
"when": {
|
||||
"opt": "contrast",
|
||||
"eq": "soft"
|
||||
},
|
||||
"colors": {
|
||||
"toolbar": "#f2e5bc",
|
||||
"panel": "#f2e5bc",
|
||||
"accent_soft": "#c3ccae",
|
||||
"hover": "#eedfb6",
|
||||
"viewport_top": "#f6edd0",
|
||||
"sketch_halo": "#f6edd0",
|
||||
"dialog_bg": "#f2e5bc",
|
||||
"glyph_bg": "#f8f2de",
|
||||
"overlay": "#f2e5bceb",
|
||||
"timeline_item": "#f2e5bc",
|
||||
"timeline_item_error": "#eabe9c",
|
||||
"field": "#f8f2de",
|
||||
"surface_soft": "#edd7ad",
|
||||
"surface_ink": "#a83803",
|
||||
"mesh_soft": "#eddcaf",
|
||||
"mesh_ink": "#84560f",
|
||||
"form_soft": "#ead8b6",
|
||||
"sheet_soft": "#e4ddb4",
|
||||
"sheet_ink": "#38694b",
|
||||
"render_soft": "#ebd3ad",
|
||||
"sketch_soft": "#e8dcae",
|
||||
"sketch_ink": "#66610c",
|
||||
"form_error_fill": "#eabe9c",
|
||||
"dialog_body": "#f2e5bc",
|
||||
"control_fill": "#f8f2de",
|
||||
"selected_bg": "#c3ccae"
|
||||
}
|
||||
},
|
||||
{
|
||||
"when": {
|
||||
"opt": "contrast",
|
||||
"eq": "hard"
|
||||
},
|
||||
"colors": {
|
||||
"toolbar": "#f9f5d7",
|
||||
"panel": "#f9f5d7",
|
||||
"accent_soft": "#c9d8c4",
|
||||
"hover": "#f1e5c1",
|
||||
"viewport_top": "#fbf8e3",
|
||||
"sketch_halo": "#fbf8e3",
|
||||
"dialog_bg": "#f9f5d7",
|
||||
"glyph_bg": "#fcfaeb",
|
||||
"overlay": "#f9f5d7eb",
|
||||
"timeline_item": "#f9f5d7",
|
||||
"timeline_item_error": "#f0cbb2",
|
||||
"field": "#fcfaeb",
|
||||
"surface_soft": "#f3e6c6",
|
||||
"mesh_soft": "#f4ebc7",
|
||||
"mesh_ink": "#915e10",
|
||||
"form_soft": "#f1e6cf",
|
||||
"sheet_soft": "#eaebcd",
|
||||
"sheet_ink": "#3d7252",
|
||||
"render_soft": "#f2e1c6",
|
||||
"sketch_soft": "#efebc7",
|
||||
"sketch_ink": "#6e6a0d",
|
||||
"form_error_fill": "#f0cbb2",
|
||||
"dialog_body": "#f9f5d7",
|
||||
"control_fill": "#fcfaeb",
|
||||
"selected_bg": "#c9d8c4"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -456,7 +456,14 @@ impl Document {
|
||||
let id = self.next_id.max(1);
|
||||
self.next_id = id.checked_add(1).ok_or_else(|| DocError::Invalid("too many items in the design".into()))?;
|
||||
let cname = self.components.iter().find(|c| c.id == component).map(|c| c.name.clone()).unwrap_or_default();
|
||||
let k = self.occurrences.iter().filter(|o| o.component == component).count() + 1;
|
||||
// The next number, or, when an occurrence already has that name (one before it was
|
||||
// deleted, or of another component of that name), the first number none has (#9738).
|
||||
let next = self.occurrences.iter().filter(|o| o.component == component).count() + 1;
|
||||
let free = |k: &usize| {
|
||||
let name = format!("{cname}:{k}");
|
||||
!self.occurrences.iter().any(|o| o.name == name)
|
||||
};
|
||||
let k = std::iter::once(next).chain(1..).find(free).unwrap_or(next);
|
||||
self.occurrences.push(crate::Occurrence { id, component, parent, name: format!("{cname}:{k}"), transform, grounded: false });
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
//! The browser's groups as a tree: how deep a group sits, who holds whom, and pruning what a
|
||||
//! saved design says about the browser down to what still exists.
|
||||
use crate::document::{BROWSER_FOLDERS, BrowserEntry, BrowserGroup, Document, MAX_GROUP_NESTING};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
impl Document {
|
||||
pub fn browser_group(&self, id: u64) -> Option<&BrowserGroup> {
|
||||
self.browser_groups.iter().find(|g| g.id == id)
|
||||
}
|
||||
|
||||
/// The level of a group: 1 for a top-level group, 2 for a child of one, and so on. A chain
|
||||
/// that loops or runs past the limit counts as one level too deep.
|
||||
pub fn group_level(&self, id: u64) -> usize {
|
||||
let mut level = 0;
|
||||
let mut at = Some(id);
|
||||
while let Some(g) = at {
|
||||
level += 1;
|
||||
if level > MAX_GROUP_NESTING {
|
||||
return level;
|
||||
}
|
||||
at = self.browser_group(g).and_then(|g| g.parent);
|
||||
}
|
||||
level
|
||||
}
|
||||
|
||||
/// Whether `ancestor` is `id` or holds it, at any depth.
|
||||
pub fn group_within(&self, id: u64, ancestor: u64) -> bool {
|
||||
let mut at = Some(id);
|
||||
for _ in 0..=MAX_GROUP_NESTING {
|
||||
match at {
|
||||
Some(g) if g == ancestor => return true,
|
||||
Some(g) => at = self.browser_group(g).and_then(|g| g.parent),
|
||||
None => return false,
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// How many levels the group and the groups under it take: 1 for a group with no child group.
|
||||
pub fn group_height(&self, id: u64) -> usize {
|
||||
fn height(d: &Document, id: u64, left: usize) -> usize {
|
||||
if left == 0 {
|
||||
return 1;
|
||||
}
|
||||
1 + d.browser_groups.iter().filter(|g| g.parent == Some(id)).map(|g| height(d, g.id, left - 1)).max().unwrap_or(0)
|
||||
}
|
||||
height(self, id, MAX_GROUP_NESTING + 1)
|
||||
}
|
||||
|
||||
/// The entries of a holder's list in display order: a group's contents, or the folder's top
|
||||
/// level when `holder` is `None`. Groups the list names come where it names them. The child
|
||||
/// groups it does not name (in creation order) go just after the last group it names, or
|
||||
/// first when it names none, so they sit above the items as they always have. Entries for
|
||||
/// groups that are not the holder's children are dropped.
|
||||
pub fn ordered_entries(&self, component: u64, folder: &str, holder: Option<u64>) -> Vec<BrowserEntry> {
|
||||
let listed: &[BrowserEntry] = match holder {
|
||||
Some(g) => self.browser_group(g).map_or(&[], |g| &g.items),
|
||||
None => self.browser_order.get(&format!("{component}/{folder}")).map_or(&[], Vec::as_slice),
|
||||
};
|
||||
let mine: Vec<u64> =
|
||||
self.browser_groups.iter().filter(|g| g.component == component && g.folder == folder && g.parent == holder).map(|g| g.id).collect();
|
||||
let mut out: Vec<BrowserEntry> = Vec::with_capacity(listed.len() + mine.len());
|
||||
for e in listed {
|
||||
match e {
|
||||
BrowserEntry::Group(id) if !mine.contains(id) || out.contains(e) => {}
|
||||
_ => out.push(e.clone()),
|
||||
}
|
||||
}
|
||||
let at = out.iter().rposition(|e| matches!(e, BrowserEntry::Group(_))).map_or(0, |i| i + 1);
|
||||
let unlisted: Vec<BrowserEntry> = mine.iter().map(|id| BrowserEntry::Group(*id)).filter(|e| !out.contains(e)).collect();
|
||||
out.splice(at..at, unlisted);
|
||||
out
|
||||
}
|
||||
|
||||
/// The items in a group and in the groups inside it.
|
||||
pub fn group_item_keys(&self, id: u64) -> Vec<String> {
|
||||
let inside = self.browser_groups.iter().filter(|g| self.group_within(g.id, id));
|
||||
inside.flat_map(|g| g.item_keys().map(str::to_string)).collect()
|
||||
}
|
||||
|
||||
/// The group holding the item directly, in a component's folder.
|
||||
pub fn group_of_item(&self, component: u64, folder: &str, key: &str) -> Option<&BrowserGroup> {
|
||||
self.browser_groups.iter().find(|g| g.component == component && g.folder == folder && g.has_item(key))
|
||||
}
|
||||
|
||||
/// Only the browser's groups and order changed (a group made, nested, moved into, ordered):
|
||||
/// nothing is evaluated and no placement moves. The same whole-Document proof as
|
||||
/// [`Document::differs_only_in_render`]; `next_id` may differ, as a new group takes an id.
|
||||
pub fn differs_only_in_browser(&self, previous: &Document) -> bool {
|
||||
if self.browser_groups == previous.browser_groups && self.browser_order == previous.browser_order {
|
||||
return false;
|
||||
}
|
||||
let mut normalized = previous.clone();
|
||||
normalized.browser_groups.clone_from(&self.browser_groups);
|
||||
normalized.browser_order.clone_from(&self.browser_order);
|
||||
normalized.next_id = self.next_id;
|
||||
*self == normalized
|
||||
}
|
||||
|
||||
/// What [`Document::browser_pruned`] depends on, cheaply: it can only find something to drop
|
||||
/// after a feature, placement, component or group was added or removed. Ids are never
|
||||
/// reused, so a removal followed by an addition still moves `next_id`.
|
||||
pub fn browser_stamp(&self) -> [u64; 6] {
|
||||
let n = |len: usize| u64::try_from(len).unwrap_or(u64::MAX);
|
||||
[
|
||||
self.next_id,
|
||||
n(self.features.len()),
|
||||
n(self.occurrences.len()),
|
||||
n(self.components.len()),
|
||||
n(self.browser_groups.len()),
|
||||
n(self.browser_order.len()),
|
||||
]
|
||||
}
|
||||
|
||||
/// The groups and order lists with what they name that is gone dropped, or `None` when
|
||||
/// nothing is: groups of a missing component or folder, a parent that is missing, elsewhere
|
||||
/// or loops, entries for groups and sketches, construction items and placements that no
|
||||
/// longer exist, repeats, and order lists of missing components. Body names are left alone:
|
||||
/// only an evaluated model knows them.
|
||||
pub fn browser_pruned(&self) -> Option<(Vec<BrowserGroup>, BTreeMap<String, Vec<BrowserEntry>>)> {
|
||||
if self.browser_groups.is_empty() && self.browser_order.is_empty() {
|
||||
return None;
|
||||
}
|
||||
let components: BTreeSet<u64> = self.components.iter().map(|c| c.id).collect();
|
||||
let features: BTreeSet<u64> = self.features.iter().map(|f| f.id).collect();
|
||||
let placed_in: BTreeMap<u64, u64> = self.occurrences.iter().map(|o| (o.id, o.parent)).collect();
|
||||
let component_exists = |c: u64| c == 0 || components.contains(&c);
|
||||
let placed = |component: u64, key: &str| key.parse::<u64>().ok().and_then(|o| placed_in.get(&o)) == Some(&component);
|
||||
// Body names cannot be checked here; the other folders hold feature ids.
|
||||
let item_exists = |folder: &str, component: u64, key: &str| match folder {
|
||||
"bodies" => true,
|
||||
"components" => placed(component, key),
|
||||
_ => key.parse::<u64>().is_ok_and(|id| features.contains(&id)),
|
||||
};
|
||||
let mut groups = self.browser_groups.clone();
|
||||
let mut order = self.browser_order.clone();
|
||||
groups.retain(|g| component_exists(g.component) && BROWSER_FOLDERS.contains(&g.folder.as_str()));
|
||||
let known: BTreeMap<u64, (u64, String)> = groups.iter().map(|g| (g.id, (g.component, g.folder.clone()))).collect();
|
||||
let parents: BTreeMap<u64, Option<u64>> = groups
|
||||
.iter()
|
||||
.map(|g| (g.id, g.parent.filter(|p| *p != g.id && known.get(p).is_some_and(|(c, f)| *c == g.component && *f == g.folder))))
|
||||
.collect();
|
||||
// A loop, or a chain too deep, is cut at the group that makes it.
|
||||
let too_deep = |id: u64| std::iter::successors(Some(id), |g| parents.get(g).copied().flatten()).nth(MAX_GROUP_NESTING).is_some();
|
||||
let kept: BTreeMap<u64, Option<u64>> = parents.iter().map(|(id, p)| (*id, if too_deep(*id) { None } else { *p })).collect();
|
||||
for g in &mut groups {
|
||||
g.parent = kept[&g.id];
|
||||
}
|
||||
let mut taken: BTreeSet<(u64, String, String)> = BTreeSet::new();
|
||||
for g in &mut groups {
|
||||
let (component, folder, id) = (g.component, g.folder.clone(), g.id);
|
||||
let mut seen = BTreeSet::new();
|
||||
g.items.retain(|e| match e {
|
||||
BrowserEntry::Group(c) => kept.get(c) == Some(&Some(id)) && seen.insert(*c),
|
||||
BrowserEntry::Item(k) => item_exists(&folder, component, k) && taken.insert((component, folder.clone(), k.clone())),
|
||||
});
|
||||
}
|
||||
let top = |c: u64, folder: &str, id: u64| kept.get(&id) == Some(&None) && known.get(&id).is_some_and(|(kc, kf)| *kc == c && kf == folder);
|
||||
order.retain(|key, list| {
|
||||
let Some((c, folder)) = key.split_once('/') else { return false };
|
||||
let Some(c) = c.parse::<u64>().ok().filter(|c| component_exists(*c)) else { return false };
|
||||
if !BROWSER_FOLDERS.contains(&folder) {
|
||||
return false;
|
||||
}
|
||||
let mut seen = BTreeSet::new();
|
||||
list.retain(|e| match e {
|
||||
BrowserEntry::Group(id) => top(c, folder, *id) && seen.insert(e.clone()),
|
||||
BrowserEntry::Item(k) => item_exists(folder, c, k) && seen.insert(e.clone()),
|
||||
});
|
||||
!list.is_empty()
|
||||
});
|
||||
(groups != self.browser_groups || order != self.browser_order).then_some((groups, order))
|
||||
}
|
||||
|
||||
/// Put placements of one component in the order the browser shows them: the saved
|
||||
/// `components` order, then the rest as they were.
|
||||
pub fn sort_placements(&self, parent: u64, ids: &mut [u64]) {
|
||||
let Some(order) = self.browser_order.get(&format!("{parent}/components")) else { return };
|
||||
let rank: BTreeMap<&str, usize> = order.iter().enumerate().filter_map(|(i, e)| Some((e.as_item()?, i))).collect();
|
||||
ids.sort_by_cached_key(|id| rank.get(id.to_string().as_str()).copied().unwrap_or(usize::MAX));
|
||||
}
|
||||
}
|
||||
@@ -176,6 +176,8 @@ pub(crate) fn remap_link(
|
||||
remap_link(b, ids, names, bodies, depth + 1);
|
||||
}
|
||||
LinkSource::Plane { name } => mapped_name(name, names),
|
||||
// A construction axis, by name (#9324); the origin axes are no feature's.
|
||||
LinkSource::Axis { name } if !matches!(name.as_str(), "X" | "Y" | "Z") => mapped_name(name, names),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,10 +344,13 @@ fn model_line(st: &ModelState, g: &GeoRef) -> Result<(Vec3, Vec3)> {
|
||||
_ => Err(bad("the face is not a cylinder, cone or torus")),
|
||||
}
|
||||
}
|
||||
_ => Err(bad("pick a straight or circular edge, or a cylinder, cone or torus face")),
|
||||
_ => Err(bad(MODEL_AXIS_REFS)),
|
||||
}
|
||||
}
|
||||
|
||||
/// What [`model_axis`] says about a reference that is neither an edge nor a face.
|
||||
pub const MODEL_AXIS_REFS: &str = "pick a straight or circular edge, or a cylinder, cone or torus face";
|
||||
|
||||
/// The axis a feature turns about when an edge or face of the model is picked for it (a revolve,
|
||||
/// a circular pattern, a plane at an angle), as [`model_line`] finds it. The direction is
|
||||
/// oriented the same way however the edge or surface runs (its largest component positive), so
|
||||
|
||||
@@ -1083,6 +1083,11 @@ pub enum FeatureKind {
|
||||
/// bodies follow. Replaces `to`.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
to_plane: Option<PlaneRef>,
|
||||
/// Point-to-point alignment: the directions the offset moves along (the chosen world
|
||||
/// X/Y/Z axes in the frame of the bodies being moved). `None`: all three axes, the
|
||||
/// offset in full.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
axes: Option<Vec<Dir>>,
|
||||
},
|
||||
/// A helical coil: a circular or square section swept `turns` times about `axis`, rising
|
||||
/// `pitch` per turn, on a helix of `diameter` (the section's centre, or its inside or outside).
|
||||
@@ -2628,6 +2633,19 @@ pub struct DesignLink {
|
||||
/// local overrides and survive a source update. Older links start with no baseline.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub inherited: Vec<LinkedBodyProperties>,
|
||||
/// SHA-256 of the design file's bytes as this design last read them ([`Self::file_digest`]):
|
||||
/// opened again, this design tells which linked files changed meanwhile (#9739). Links made
|
||||
/// before it was kept have none and are taken as up to date.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub file_sha256: Option<String>,
|
||||
}
|
||||
|
||||
impl DesignLink {
|
||||
/// What [`Self::file_sha256`] keeps for a design file's `bytes`.
|
||||
pub fn file_digest(bytes: &[u8]) -> String {
|
||||
use sha2::{Digest, Sha256};
|
||||
format!("{:x}", Sha256::digest(bytes))
|
||||
}
|
||||
}
|
||||
|
||||
/// The values last inherited by a linked body, not another editable material library.
|
||||
@@ -2736,6 +2754,9 @@ pub struct Document {
|
||||
/// Physical material per body (by body name); others use the default.
|
||||
#[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
|
||||
pub materials: std::collections::BTreeMap<String, String>,
|
||||
/// The flat face per body (by body name) that a slicer export lays on the print bed.
|
||||
#[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
|
||||
pub print_faces: std::collections::BTreeMap<String, crate::config::ConfigFaceTarget>,
|
||||
/// Physical materials defined in this design (`material.create`), next to the built-in ones.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub user_materials: Vec<UserMaterial>,
|
||||
@@ -2756,9 +2777,11 @@ pub struct Document {
|
||||
/// order; feature ids remain the source of truth when features are renamed or reordered.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub timeline_groups: Vec<TimelineGroup>,
|
||||
/// Browser item order per component folder (`"<component>/<folder>"` → item keys).
|
||||
/// Browser order per component folder (`"<component>/<folder>"` → groups and item keys).
|
||||
/// The `components` folder orders a component's sub-components (by placement id); it is not
|
||||
/// drawn as a folder.
|
||||
#[serde(default, skip_serializing_if = "std::collections::BTreeMap::is_empty")]
|
||||
pub browser_order: std::collections::BTreeMap<String, Vec<String>>,
|
||||
pub browser_order: std::collections::BTreeMap<String, Vec<BrowserEntry>>,
|
||||
/// Named views: saved cameras.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub named_views: Vec<NamedView>,
|
||||
@@ -2847,8 +2870,69 @@ pub struct BrowserGroup {
|
||||
#[serde(default)]
|
||||
pub component: u64,
|
||||
pub folder: String,
|
||||
/// The group that holds this one; `None` is the top level of its folder.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub parent: Option<u64>,
|
||||
/// The group's items and child groups in display order. A child group missing here still
|
||||
/// belongs to it (its `parent` says so) and is listed after the ones that are here.
|
||||
#[serde(default)]
|
||||
pub items: Vec<String>,
|
||||
pub items: Vec<BrowserEntry>,
|
||||
}
|
||||
|
||||
/// One line of a browser order list: a group (a number in a saved design) or an item (a string:
|
||||
/// an item key or body name, so a body named `"1"` never clashes with group 1).
|
||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum BrowserEntry {
|
||||
Group(u64),
|
||||
Item(String),
|
||||
}
|
||||
|
||||
impl From<&str> for BrowserEntry {
|
||||
fn from(key: &str) -> Self {
|
||||
BrowserEntry::Item(key.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for BrowserEntry {
|
||||
fn from(key: String) -> Self {
|
||||
BrowserEntry::Item(key)
|
||||
}
|
||||
}
|
||||
|
||||
impl BrowserEntry {
|
||||
pub fn item(key: &str) -> Self {
|
||||
BrowserEntry::Item(key.to_string())
|
||||
}
|
||||
|
||||
pub fn as_item(&self) -> Option<&str> {
|
||||
match self {
|
||||
BrowserEntry::Item(k) => Some(k),
|
||||
BrowserEntry::Group(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_item(&self, key: &str) -> bool {
|
||||
self.as_item() == Some(key)
|
||||
}
|
||||
}
|
||||
|
||||
/// How many groups may sit inside one another (a top-level group is level 1).
|
||||
pub const MAX_GROUP_NESTING: usize = 8;
|
||||
|
||||
/// The folders a browser group or order list can be for. `components` only orders sub-components.
|
||||
pub const BROWSER_FOLDERS: [&str; 4] = ["bodies", "sketches", "construction", "components"];
|
||||
|
||||
impl BrowserGroup {
|
||||
/// The keys of the items directly in this group, in order.
|
||||
pub fn item_keys(&self) -> impl Iterator<Item = &str> {
|
||||
self.items.iter().filter_map(BrowserEntry::as_item)
|
||||
}
|
||||
|
||||
/// Whether this group holds the item directly.
|
||||
pub fn has_item(&self, key: &str) -> bool {
|
||||
self.items.iter().any(|e| e.is_item(key))
|
||||
}
|
||||
}
|
||||
|
||||
/// A saved history folder. Folders may nest; each feature or joint belongs to at most one folder.
|
||||
@@ -2982,6 +3066,7 @@ impl Document {
|
||||
body_components: Default::default(),
|
||||
body_offsets: Default::default(),
|
||||
materials: Default::default(),
|
||||
print_faces: Default::default(),
|
||||
user_materials: Vec::new(),
|
||||
appearances: Default::default(),
|
||||
favorites: Default::default(),
|
||||
@@ -2997,7 +3082,7 @@ impl Document {
|
||||
}
|
||||
|
||||
/// Rename body `old` to `new` where the design keeps things by body name outside its
|
||||
/// features: materials, appearances, plastic rules, configuration columns, offsets, components and the
|
||||
/// features: materials, print faces, appearances, plastic rules, configuration columns, offsets, components and the
|
||||
/// browser's groups and order. (The features are the rename command's to change.)
|
||||
///
|
||||
/// A name the design numbered (`Body1`) is not used again after the rename: the design's
|
||||
@@ -3013,6 +3098,10 @@ impl Document {
|
||||
if let Some(m) = self.materials.remove(old) {
|
||||
self.materials.insert(new.to_string(), m);
|
||||
}
|
||||
if let Some(mut face) = self.print_faces.remove(old) {
|
||||
face.body = new.to_string();
|
||||
self.print_faces.insert(new.to_string(), face);
|
||||
}
|
||||
if let Some(rule) = self.plastic.assigned.remove(old) {
|
||||
self.plastic.assigned.insert(new.to_string(), rule);
|
||||
}
|
||||
@@ -3039,15 +3128,16 @@ impl Document {
|
||||
if let Some(c) = self.body_components.remove(old) {
|
||||
self.body_components.insert(new.to_string(), c);
|
||||
}
|
||||
for g in self.browser_groups.iter_mut().filter(|g| g.folder == "bodies") {
|
||||
for k in g.items.iter_mut().filter(|k| *k == old) {
|
||||
*k = new.to_string();
|
||||
let rename = |e: &mut BrowserEntry| {
|
||||
if e.is_item(old) {
|
||||
*e = BrowserEntry::item(new);
|
||||
}
|
||||
};
|
||||
for g in self.browser_groups.iter_mut().filter(|g| g.folder == "bodies") {
|
||||
g.items.iter_mut().for_each(rename);
|
||||
}
|
||||
for (_, v) in self.browser_order.iter_mut().filter(|(k, _)| k.ends_with("/bodies")) {
|
||||
for k in v.iter_mut().filter(|k| *k == old) {
|
||||
*k = new.to_string();
|
||||
}
|
||||
v.iter_mut().for_each(rename);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3366,10 +3456,14 @@ impl Document {
|
||||
/// Read a design file's JSON (any format this build knows; older ones are upgraded).
|
||||
pub fn from_json(s: &str) -> Result<Document> {
|
||||
crate::render_resources::check_json_budget(s)?;
|
||||
let d = crate::format::read(s)?;
|
||||
let mut d = crate::format::read(s)?;
|
||||
if d.features.len() > MAX_FEATURES || d.params.len() > MAX_PARAMS {
|
||||
return Err(DocError::Invalid("document too large".into()));
|
||||
}
|
||||
// A design from elsewhere may nest groups too deep, loop, or name things that are gone.
|
||||
if let Some((groups, order)) = d.browser_pruned() {
|
||||
(d.browser_groups, d.browser_order) = (groups, order);
|
||||
}
|
||||
Ok(d)
|
||||
}
|
||||
pub fn to_json(&self) -> String {
|
||||
@@ -3395,15 +3489,35 @@ impl Document {
|
||||
self.features.iter().find(|f| f.name.eq_ignore_ascii_case(r))
|
||||
}
|
||||
|
||||
/// Resolve a textual timeline reference. An exact name wins even when it looks like an id.
|
||||
/// Older scripts also pass ids as strings or use a different case for a unique name.
|
||||
pub fn resolve_feature_name(&self, name: &str) -> Result<&Feature> {
|
||||
if let Some(feature) = self.features.iter().find(|f| f.name == name) {
|
||||
return Ok(feature);
|
||||
}
|
||||
if let Ok(id) = name.parse::<u64>()
|
||||
&& let Some(feature) = self.feature(id)
|
||||
{
|
||||
return Ok(feature);
|
||||
}
|
||||
let mut matches = self.features.iter().filter(|f| f.name.eq_ignore_ascii_case(name));
|
||||
let feature = matches.next().ok_or_else(|| DocError::Invalid(format!("no feature `{name}`")))?;
|
||||
if matches.next().is_some() {
|
||||
return Err(DocError::Invalid(format!("ambiguous feature `{name}`. Use its exact name or numeric id")));
|
||||
}
|
||||
Ok(feature)
|
||||
}
|
||||
|
||||
/// The feature a pattern or mirror seed names, resolved the way `replay()` resolved seed
|
||||
/// names before seeds were keyed by id (#1134): an exact name match on a feature that is
|
||||
/// not a sketch or a construction plane wins — a sketch and its extrude often share a
|
||||
/// name, and the feature that makes geometry is the one to copy — else [`find_feature`].
|
||||
/// name, and the feature that makes geometry is the one to copy. Other references use
|
||||
/// the timeline lookup.
|
||||
pub fn seed_feature(&self, name: &str) -> Option<&Feature> {
|
||||
self.features
|
||||
.iter()
|
||||
.find(|x| x.name == name && !matches!(x.kind, FeatureKind::Sketch { .. } | FeatureKind::ConstructionPlane { .. }))
|
||||
.or_else(|| self.find_feature(name))
|
||||
.or_else(|| self.resolve_feature_name(name).ok())
|
||||
}
|
||||
|
||||
fn unique_name(&self, base: &str) -> String {
|
||||
@@ -4014,7 +4128,7 @@ impl Document {
|
||||
return Err(DocError::Invalid("a text's height must be positive".into()));
|
||||
}
|
||||
if let Some(e) = &exprs.text {
|
||||
let words = self.eval_words(e).map_err(|error| DocError::Expr(format!("text: {error}")))?;
|
||||
let words = self.eval_words(e, vals).map_err(|error| DocError::Expr(format!("text: {error}")))?;
|
||||
if words.trim().is_empty() || words.chars().count() > solidcraft_sketch::MAX_TEXT_CHARS {
|
||||
return Err(DocError::Invalid(format!("text: `{e}` gives no words, or too many")));
|
||||
}
|
||||
@@ -4097,6 +4211,14 @@ impl Document {
|
||||
} else {
|
||||
solidcraft_sketch::solve_after_edit_with_analysis(sk, stored, was(sk).as_deref(), analysis)
|
||||
};
|
||||
// An attachment to the old offset can prevent the source from moving at all.
|
||||
// Retry from a source-only seed, adopting it only if every constraint still holds.
|
||||
if !report.ok()
|
||||
&& report.oversized.is_none()
|
||||
&& let Some(retried) = sk.solve_after_offset_edit(stored, was(sk).as_deref(), analysis)
|
||||
{
|
||||
report = retried;
|
||||
}
|
||||
}
|
||||
Ok(report)
|
||||
}
|
||||
|
||||
@@ -792,6 +792,11 @@ fn split_piece_of(name: &str) -> Option<&str> {
|
||||
(!n.starts_with('0') && n.parse::<u32>().is_ok()).then_some(base)
|
||||
}
|
||||
|
||||
/// The warning of a sketch whose profile search was cut short (#6896).
|
||||
fn profiles_cut_short_note() -> String {
|
||||
format!("some profiles may be missing: a group of touching curves is cut into more than {} pieces", solidcraft_sketch::MAX_PROFILE_EDGES)
|
||||
}
|
||||
|
||||
/// Add `note` to a feature's warning.
|
||||
fn append_warning(warning: &mut Option<String>, note: String) {
|
||||
*warning = Some(match warning.take() {
|
||||
@@ -1189,13 +1194,21 @@ impl ModelState {
|
||||
/// to the budget keep only its last few states, so setting a parameter back recomputed what
|
||||
/// had dropped out.
|
||||
fn added_bytes(&self, before: &ModelState) -> usize {
|
||||
// `before`'s bodies by solid, and its sketches by address: looked up per body and sketch,
|
||||
// not searched (every feature's result is charged, so searching was bodies² per feature).
|
||||
// Bodies sharing a solid are still told apart by `same_shape` (the mesh as well).
|
||||
let mut solids: std::collections::HashMap<usize, Vec<&Body>> = std::collections::HashMap::with_capacity(before.bodies.len());
|
||||
for o in &before.bodies {
|
||||
solids.entry(o.body.solid_id()).or_default().push(&o.body);
|
||||
}
|
||||
let bodies: usize = self
|
||||
.bodies
|
||||
.iter()
|
||||
.filter(|b| !before.bodies.iter().any(|o| o.body.same_shape(&b.body)))
|
||||
.filter(|b| !solids.get(&b.body.solid_id()).is_some_and(|os| os.iter().any(|o| o.same_shape(&b.body))))
|
||||
.map(|b| if b.bytes > 0 { b.bytes } else { b.body.retained_bytes() })
|
||||
.sum();
|
||||
let sketches: usize = self.sketches.iter().filter(|s| !before.sketches.iter().any(|o| Arc::ptr_eq(o, s))).map(|s| s.retained_bytes()).sum();
|
||||
let kept: std::collections::HashSet<*const SolvedSketch> = before.sketches.iter().map(Arc::as_ptr).collect();
|
||||
let sketches: usize = self.sketches.iter().filter(|s| !kept.contains(&Arc::as_ptr(s))).map(|s| s.retained_bytes()).sum();
|
||||
bodies + sketches + self.sheets.len() * 4096 + self.threads.len() * 192 + self.construct.len() * 192
|
||||
}
|
||||
|
||||
@@ -1294,6 +1307,10 @@ pub struct Model {
|
||||
kept: KeptSlot,
|
||||
/// The imported texts' digests the last `evaluate` fingerprinted the features with.
|
||||
step_digests: StepDigests,
|
||||
/// The address of the shared document whose fingerprints the results were last given in
|
||||
/// full, with [`fingerprints_digest`] of them then ([`Model::pinned_prefix`]). Only an
|
||||
/// address: a reference to the document would make every in-place edit of it a copy.
|
||||
fingerprinted: Option<(usize, u64)>,
|
||||
/// The document context the last `evaluate` ran in ([`context_digest`]).
|
||||
context: u64,
|
||||
/// The last active result of each feature hidden by the history marker, with its document
|
||||
@@ -1413,32 +1430,40 @@ fn quantize(sk: &mut solidcraft_sketch::Sketch) {
|
||||
/// file's text by its digest.
|
||||
/// Hash [`feature_json`] of `f` into `h`. Every evaluation fingerprints every feature, and in a
|
||||
/// design built command by command almost all of them are the same as last time: the text of a
|
||||
/// feature is kept (per thread, by id) with the feature it was written from, and written again
|
||||
/// only when the feature differs. An Import's text also depends on its STEP digest, so it is
|
||||
/// written each time as before.
|
||||
/// feature is kept (by id) with the feature it was written from, and written again only when the
|
||||
/// feature differs. An Import's text also depends on its STEP digest, so it is written each time
|
||||
/// as before.
|
||||
///
|
||||
/// The texts are shared by every thread: a command evaluated ahead runs on a new worker thread
|
||||
/// each time (the desktop's deferred commands and delete checks, the control channel's ahead
|
||||
/// jobs), and a per-thread store started empty there, so every ahead run wrote out every
|
||||
/// feature again. The lock is held only to look up or store an entry, never while a feature is
|
||||
/// compared or written; an entry is the same whichever thread wrote it, since the text is a
|
||||
/// function of the feature alone.
|
||||
fn hash_feature_json(f: &Feature, steps: &StepDigests, h: &mut impl Hasher) {
|
||||
type Written = std::collections::HashMap<u64, Arc<(Feature, String)>>;
|
||||
static WRITTEN: std::sync::LazyLock<std::sync::Mutex<Written>> = std::sync::LazyLock::new(Default::default);
|
||||
if matches!(f.kind, FeatureKind::Import { .. }) {
|
||||
feature_json(f, steps).hash(h);
|
||||
return;
|
||||
}
|
||||
thread_local! {
|
||||
static WRITTEN: std::cell::RefCell<std::collections::HashMap<u64, (Feature, String)>> = std::cell::RefCell::new(std::collections::HashMap::new());
|
||||
let seen = WRITTEN.lock().unwrap_or_else(|e| e.into_inner()).get(&f.id).cloned();
|
||||
if let Some(seen) = seen
|
||||
&& seen.0 == *f
|
||||
{
|
||||
seen.1.hash(h);
|
||||
return;
|
||||
}
|
||||
WRITTEN.with(|written| {
|
||||
let mut written = written.borrow_mut();
|
||||
if let Some((seen, json)) = written.get(&f.id)
|
||||
&& seen == f
|
||||
{
|
||||
json.hash(h);
|
||||
return;
|
||||
}
|
||||
let json = feature_json(f, steps);
|
||||
json.hash(h);
|
||||
if written.len() >= 1 << 15 {
|
||||
written.clear();
|
||||
}
|
||||
written.insert(f.id, (f.clone(), json));
|
||||
});
|
||||
#[cfg(test)]
|
||||
cost_tests::count_written();
|
||||
let json = feature_json(f, steps);
|
||||
json.hash(h);
|
||||
let entry = Arc::new((f.clone(), json));
|
||||
let mut written = WRITTEN.lock().unwrap_or_else(|e| e.into_inner());
|
||||
if written.len() >= 1 << 15 {
|
||||
written.clear();
|
||||
}
|
||||
written.insert(f.id, entry);
|
||||
}
|
||||
|
||||
fn feature_json(f: &Feature, steps: &StepDigests) -> String {
|
||||
@@ -2126,6 +2151,7 @@ impl Model {
|
||||
/// Re-evaluate the document, reusing results up to the first changed feature.
|
||||
pub fn evaluate(&mut self, doc: &Document) {
|
||||
self.placement_inputs = None;
|
||||
self.fingerprinted = None;
|
||||
self.placement_local = true;
|
||||
let (vals, perr) = evaluation_values(doc);
|
||||
self.param_errors = perr;
|
||||
@@ -2153,7 +2179,14 @@ impl Model {
|
||||
feature_component.entry(f.id).or_insert(f.component);
|
||||
}
|
||||
let watched = crate::progress::begin(doc.features.len());
|
||||
// The features that failed so far in this pass, by id: their names and errors (#9075).
|
||||
let mut failed: std::collections::HashMap<u64, (String, String)> = std::collections::HashMap::new();
|
||||
for (i, f) in doc.features.iter().enumerate() {
|
||||
if let Some(r) = out.last()
|
||||
&& let Some(e) = &r.error
|
||||
{
|
||||
failed.insert(r.id, (r.name.clone(), e.clone()));
|
||||
}
|
||||
self.placement_local = self.placement_local && placement_reuse::local_geometry(f, &feature_component);
|
||||
let rolled_back = i >= marker;
|
||||
// Retain at most one active result per rolled-back feature, even across several
|
||||
@@ -2213,6 +2246,33 @@ impl Model {
|
||||
if state.reserved_body_names != reserved {
|
||||
Arc::make_mut(&mut state).reserved_body_names.clone_from(&reserved);
|
||||
}
|
||||
// A sketch the feature is built from failed earlier in this pass: the feature fails naming
|
||||
// that sketch, with its error, as one using a failed parameter does (#9075), not as a
|
||||
// sketch that must come earlier in the timeline. Never cached: the cache key holds
|
||||
// neither the sketch's name nor its error (a rename, another failing value).
|
||||
let failed_sketch = if failed.is_empty() {
|
||||
None
|
||||
} else {
|
||||
f.kind.input_sketches().into_iter().find_map(|id| failed.get(&id)).map(|(name, e)| format!("sketch `{name}` failed: {e}"))
|
||||
};
|
||||
if let Some(e) = failed_sketch {
|
||||
recomputed += 1;
|
||||
reuse = false;
|
||||
out.push(FeatureResult {
|
||||
id: f.id,
|
||||
name: f.name.clone(),
|
||||
error: Some(e),
|
||||
warning: None,
|
||||
boolean_diagnostics: Default::default(),
|
||||
ms: 0.0,
|
||||
skipped: false,
|
||||
stale: false,
|
||||
fingerprint: fp,
|
||||
unkept: false,
|
||||
state: state.clone(),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
// The same feature on the same inputs: its earlier result.
|
||||
let key =
|
||||
cache_key(f, fp, fingerprint(doc, 0, f, &vals, false, &self.step_digests) ^ placement_digest(doc, f, Some(&state)), ctx, &state);
|
||||
@@ -2493,19 +2553,76 @@ impl Model {
|
||||
/// Set every result's fingerprint to `doc`'s, so the next evaluation reuses every result
|
||||
/// (after a change that builds nothing differently).
|
||||
pub fn refingerprint(&mut self, doc: &Document) {
|
||||
self.refingerprint_from(doc, 0);
|
||||
}
|
||||
|
||||
/// How many leading results keep their fingerprints when `doc` has the body names of the
|
||||
/// features `renamed` pinned, and nothing else changed (see [`Model::refingerprint_shared`]).
|
||||
/// Every command pins, and fingerprinting the whole timeline again for it cost as much as
|
||||
/// the fingerprinting of the evaluation itself. When the results hold `doc`'s fingerprints
|
||||
/// (the address and digest kept when they were given prove it), those before the first
|
||||
/// renamed feature stand, since nothing they read changes, unless a pattern or mirror of
|
||||
/// features among them replays a renamed one (it fingerprints its sources' definitions
|
||||
/// wherever they are). Without that proof: none.
|
||||
pub fn pinned_prefix(&self, doc: &Arc<Document>, renamed: &[u64]) -> usize {
|
||||
let proven = self.fingerprinted.is_some_and(|(of, digest)| of == Arc::as_ptr(doc) as usize && digest == fingerprints_digest(&self.results));
|
||||
if !proven {
|
||||
return 0;
|
||||
}
|
||||
let Some(first) = doc.features.iter().position(|f| renamed.contains(&f.id)) else { return doc.features.len() };
|
||||
let replays_renamed = |f: &Feature| match &f.kind {
|
||||
FeatureKind::Pattern { features, bodies, .. } | FeatureKind::Mirror { features, bodies, .. } => {
|
||||
bodies.is_empty() && !features.is_empty() && replayed_sources(doc, features).iter().any(|g| renamed.contains(&g.id))
|
||||
}
|
||||
_ => false,
|
||||
};
|
||||
doc.features.iter().take(first).position(replays_renamed).unwrap_or(first)
|
||||
}
|
||||
|
||||
/// Drop the proof [`Model::pinned_prefix`] reads: the document at that address is about to
|
||||
/// change in place.
|
||||
pub fn forget_fingerprints(&mut self) {
|
||||
self.fingerprinted = None;
|
||||
}
|
||||
|
||||
/// Fingerprint the results from `start` on for `doc`, chained onto the fingerprint before.
|
||||
pub(crate) fn refingerprint_from(&mut self, doc: &Document, start: usize) {
|
||||
self.placement_inputs = None;
|
||||
self.fingerprinted = None;
|
||||
self.step_digests = StepDigests::of(doc, &self.step_digests);
|
||||
let start = start.min(self.results.len()).min(doc.features.len());
|
||||
if start == self.results.len().min(doc.features.len()) {
|
||||
return;
|
||||
}
|
||||
let (vals, _) = evaluation_values(doc);
|
||||
let marker = doc.marker.unwrap_or(usize::MAX);
|
||||
self.step_digests = StepDigests::of(doc, &self.step_digests);
|
||||
let mut prev = 0;
|
||||
let last = start.checked_sub(1).and_then(|i| self.results.get(i));
|
||||
let mut prev = last.map_or(0, |r| r.fingerprint);
|
||||
// Each feature's fingerprint reads the model it starts from, as evaluating does.
|
||||
let mut before = Arc::new(ModelState::default());
|
||||
for (i, (r, f)) in self.results.iter_mut().zip(&doc.features).enumerate() {
|
||||
let mut before = last.map_or_else(|| Arc::new(ModelState::default()), |r| r.state.clone());
|
||||
for (i, (r, f)) in self.results.iter_mut().zip(&doc.features).enumerate().skip(start) {
|
||||
prev = chain_fingerprint(doc, &vals, f, prev, i >= marker, &self.step_digests, Some(&before));
|
||||
r.fingerprint = prev;
|
||||
before = r.state.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/// Note that the results now hold `doc`'s fingerprints (for [`Model::pinned_prefix`]).
|
||||
pub(crate) fn mark_fingerprinted(&mut self, doc: &Arc<Document>) {
|
||||
self.fingerprinted = Some((Arc::as_ptr(doc) as usize, fingerprints_digest(&self.results)));
|
||||
}
|
||||
}
|
||||
|
||||
/// A digest of the results' features and fingerprints, which proves they are still the ones
|
||||
/// [`Model::mark_fingerprinted`] saw (whatever changed them since).
|
||||
fn fingerprints_digest(results: &[FeatureResult]) -> u64 {
|
||||
let mut h = std::collections::hash_map::DefaultHasher::new();
|
||||
results.len().hash(&mut h);
|
||||
for r in results {
|
||||
r.id.hash(&mut h);
|
||||
r.fingerprint.hash(&mut h);
|
||||
}
|
||||
h.finish()
|
||||
}
|
||||
|
||||
/// Key of the design's length unit (mm per unit) among the values (no parameter can be named
|
||||
@@ -3199,6 +3316,11 @@ fn apply_traced_with(
|
||||
// Not yet: a cut that splits one piece of such a body still splits all of them; keeping
|
||||
// the untouched ones together needs each new piece traced to the piece it came from.
|
||||
let mut taken: std::collections::BTreeSet<String> = state.bodies.iter().map(|b| b.name.clone()).collect();
|
||||
// The pieces past the first belong to this feature, like a split's pieces (#10123):
|
||||
// `body.rename` stores their names in this feature's `body_names`, in this order, so a
|
||||
// renamed piece keeps its own name through a rebuild instead of landing on a sibling
|
||||
// of the body it was cut from.
|
||||
let mut extra = 0usize;
|
||||
let mut split: Vec<ModelBody> = Vec::new();
|
||||
for mb in std::mem::take(&mut state.bodies) {
|
||||
let Some(&had) = affected.get(&mb.name).filter(|_| !state.sheets.iter().any(|s| s.body == mb.name)) else {
|
||||
@@ -3214,13 +3336,18 @@ fn apply_traced_with(
|
||||
// (so pieces of one face in different bodies are told apart).
|
||||
let lineages = crate::lineage::Lineage::lumps(&mb.body, mb.lineage().as_deref(), &pieces);
|
||||
for (k, (p, lineage)) in pieces.into_iter().zip(lineages).enumerate() {
|
||||
let name = if k == 0 {
|
||||
mb.name.clone()
|
||||
let (name, made_by) = if k == 0 {
|
||||
(mb.name.clone(), mb.feature)
|
||||
} else {
|
||||
(k..=k + taken.len()).map(|j| format!("{} ({j})", mb.name)).find(|n| !taken.contains(n)).unwrap_or_default()
|
||||
let stored = f.body_names.get(extra).filter(|n| !n.trim().is_empty() && !taken.contains(*n)).cloned();
|
||||
extra += 1;
|
||||
let name = stored.unwrap_or_else(|| {
|
||||
(k..=k + taken.len()).map(|j| format!("{} ({j})", mb.name)).find(|n| !taken.contains(n)).unwrap_or_default()
|
||||
});
|
||||
(name, f.id)
|
||||
};
|
||||
taken.insert(name.clone());
|
||||
split.push(ModelBody::new(name, p, mb.feature).with_lineage(lineage));
|
||||
split.push(ModelBody::new(name, p, made_by).with_lineage(lineage));
|
||||
}
|
||||
}
|
||||
state.bodies = split;
|
||||
@@ -7223,7 +7350,13 @@ fn eval_feature(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st:
|
||||
*warning = Some(warns.join("; "));
|
||||
}
|
||||
sk.validate_periodic_splines()?;
|
||||
let profiles = find_profiles(&sk);
|
||||
// A group of touching curves too large to search whole says so, rather than
|
||||
// leaving profiles out silently (#6896).
|
||||
let search = solidcraft_sketch::find_profiles_checked(&sk);
|
||||
if search.incomplete {
|
||||
append_warning(warning, profiles_cut_short_note());
|
||||
}
|
||||
let profiles = search.profiles;
|
||||
let ends = solidcraft_sketch::loose_ends(&sk);
|
||||
st.sketches.retain(|s| s.feature != f.id);
|
||||
st.sketches.push(Arc::new(SolvedSketch { feature: f.id, name: f.name.clone(), plane, sketch: sk, report, profiles, ends }));
|
||||
|
||||
@@ -36,6 +36,22 @@ pub(super) fn count(f: impl FnOnce(&mut Counts)) {
|
||||
});
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static WRITTEN: Cell<usize> = const { Cell::new(0) };
|
||||
}
|
||||
|
||||
/// A feature written out on this thread to be fingerprinted.
|
||||
pub(super) fn count_written() {
|
||||
WRITTEN.with(|c| c.set(c.get() + 1));
|
||||
}
|
||||
|
||||
/// The features `f` writes out on this thread to fingerprint them.
|
||||
fn written(f: impl FnOnce()) -> usize {
|
||||
WRITTEN.with(|c| c.set(0));
|
||||
f();
|
||||
WRITTEN.with(Cell::get)
|
||||
}
|
||||
|
||||
/// The work `f` does on this thread.
|
||||
fn counted(f: impl FnOnce()) -> Counts {
|
||||
COUNTS.with(|c| c.set(Counts::default()));
|
||||
@@ -358,6 +374,132 @@ fn an_imported_file_is_fingerprinted_by_its_text() {
|
||||
assert_eq!(model.state().bodies.len(), 3);
|
||||
}
|
||||
|
||||
/// Pinning body names fingerprints the timeline again only from the first renamed feature on
|
||||
/// (`Model::pinned_prefix`), and gives the fingerprints the full pass gives: random pins
|
||||
/// on a timeline of boxes, cuts, patterns of features (one placed before its source, as one made
|
||||
/// with the timeline rolled back is), a suppressed feature and a history marker, after an
|
||||
/// evaluation and after earlier pins.
|
||||
#[test]
|
||||
fn pinning_body_names_fingerprints_as_the_full_pass_does() {
|
||||
let kind = |v: serde_json::Value| serde_json::from_value::<FeatureKind>(v).unwrap();
|
||||
let mut doc = Document::new("pins");
|
||||
let mut ids = Vec::new();
|
||||
for i in 0..10 {
|
||||
let x = 20.0 * i as f64;
|
||||
let b =
|
||||
kind(serde_json::json!({"type": "box", "corner": [x, 0.0, 0.0], "length": "10", "width": "10", "height": "10", "operation": "new_body"}));
|
||||
ids.push(doc.add_feature(b, None).unwrap());
|
||||
if i % 3 == 1 {
|
||||
let c = kind(
|
||||
serde_json::json!({"type": "cylinder", "axis": [0.0, 0.0, 1.0], "base": [x + 5.0, 5.0, -1.0], "height": "12", "radius": "2", "operation": "cut"}),
|
||||
);
|
||||
ids.push(doc.add_feature(c, None).unwrap());
|
||||
}
|
||||
}
|
||||
let circular = |features: Vec<u64>| {
|
||||
kind(serde_json::json!({"type": "pattern", "features": features, "bodies": [],
|
||||
"pattern": {"type": "circular", "angle": "360 deg", "axis": [0.0, 0.0, 1.0], "count": "3", "origin": [0.0, -40.0, 0.0]}}))
|
||||
};
|
||||
ids.push(doc.add_feature(circular(vec![ids[2]]), None).unwrap());
|
||||
// A pattern of a later feature, placed early in the timeline.
|
||||
let early = doc.add_feature(circular(vec![ids[9]]), None).unwrap();
|
||||
let at = doc.features.iter().position(|f| f.id == early).unwrap();
|
||||
let f = doc.features.remove(at);
|
||||
doc.features.insert(3, f);
|
||||
ids.push(early);
|
||||
doc.feature_mut(ids[5]).unwrap().suppressed = true;
|
||||
|
||||
let mut seed = 0x2545_f491_4f6c_dd1du64;
|
||||
let mut next = |n: usize| {
|
||||
seed ^= seed << 13;
|
||||
seed ^= seed >> 7;
|
||||
seed ^= seed << 17;
|
||||
(seed % n as u64) as usize
|
||||
};
|
||||
let fps = |m: &Model| m.results.iter().map(|r| (r.id, r.fingerprint)).collect::<Vec<_>>();
|
||||
let mut old = Arc::new(doc);
|
||||
let mut model = Model::new();
|
||||
model.evaluate_shared(&old);
|
||||
let (mut proven, mut kept) = (0, 0);
|
||||
for round in 0..60 {
|
||||
if round % 20 == 10 {
|
||||
// From an evaluation's fingerprints again, with the marker in some rounds.
|
||||
let mut d = (*old).clone();
|
||||
d.marker = (round == 30).then_some(d.features.len() - 2);
|
||||
old = Arc::new(d);
|
||||
model.evaluate_shared(&old);
|
||||
}
|
||||
let mut new = (*old).clone();
|
||||
let mut renamed = Vec::new();
|
||||
for _ in 0..1 + next(3) {
|
||||
let f = &mut new.features[next(old.features.len())];
|
||||
let slot = next(3);
|
||||
f.body_names.resize(f.body_names.len().max(slot + 1), String::new());
|
||||
f.body_names[slot] = format!("Pinned {round} {slot}");
|
||||
renamed.push(f.id);
|
||||
}
|
||||
new.reserved_body_names.insert(format!("Body{}", 100 + round));
|
||||
let new = Arc::new(new);
|
||||
let start = model.pinned_prefix(&old, &renamed);
|
||||
let first = new.features.iter().position(|f| renamed.contains(&f.id)).unwrap();
|
||||
assert!(start <= first, "round {round}: kept {start} past the first renamed feature {first}");
|
||||
proven += usize::from(start > 0);
|
||||
kept += start;
|
||||
let mut partial = model.clone();
|
||||
partial.refingerprint_shared(&new, start);
|
||||
let mut full = model.clone();
|
||||
full.refingerprint_shared(&new, 0);
|
||||
assert_eq!(fps(&partial), fps(&full), "round {round}");
|
||||
assert_ne!(fps(&partial), fps(&model), "round {round}: the names are fingerprinted");
|
||||
// The pinned fingerprints prove themselves for the next pin, as the full pass's do.
|
||||
assert_eq!(partial.fingerprinted.as_ref().map(|(_, d)| *d), full.fingerprinted.as_ref().map(|(_, d)| *d));
|
||||
model = partial;
|
||||
old = new;
|
||||
}
|
||||
assert!(proven > 40 && kept > 0, "the stored fingerprints were reused: {proven} rounds, {kept} results");
|
||||
|
||||
// No proof, no reuse: results changed since, another design, or the design about to change
|
||||
// in place.
|
||||
let last = [*ids.last().unwrap()];
|
||||
assert!(model.pinned_prefix(&old, &last) > 0);
|
||||
let mut changed = model.clone();
|
||||
changed.results[0].fingerprint ^= 1;
|
||||
assert_eq!(changed.pinned_prefix(&old, &last), 0);
|
||||
assert_eq!(model.pinned_prefix(&Arc::new((*old).clone()), &last), 0);
|
||||
let mut forgot = model.clone();
|
||||
forgot.forget_fingerprints();
|
||||
assert_eq!(forgot.pinned_prefix(&old, &last), 0);
|
||||
}
|
||||
|
||||
/// A design evaluated ahead, on a worker thread of its own, fingerprints its features from the
|
||||
/// texts the window's evaluation wrote: none is written out again there (the store was per
|
||||
/// thread, and every ahead run started it empty), and the fingerprints are the same.
|
||||
#[test]
|
||||
fn an_evaluation_on_another_thread_reuses_the_written_features() {
|
||||
let mut doc = Document::new("ahead");
|
||||
// Ids no other test's design uses: the store is shared by the tests running beside this one.
|
||||
doc.next_id = 0x0007_e57a_4ead_0000;
|
||||
for i in 0..40 {
|
||||
let x = 20.0 * i as f64;
|
||||
let b = serde_json::json!({"type": "box", "corner": [x, 0.0, 0.0], "length": "10", "width": "10", "height": "10", "operation": "new_body"});
|
||||
doc.add_feature(serde_json::from_value(b).unwrap(), None).unwrap();
|
||||
}
|
||||
let mut window = Model::new();
|
||||
let first = written(|| window.evaluate(&doc));
|
||||
assert!(first >= doc.features.len(), "{first} written");
|
||||
let fps = |m: &Model| m.results.iter().map(|r| r.fingerprint).collect::<Vec<_>>();
|
||||
let (doc2, mut ahead) = (doc.clone(), window.clone());
|
||||
ahead.no_cache = true;
|
||||
let (work, ahead_fps) = std::thread::spawn(move || {
|
||||
let work = written(|| ahead.evaluate(&doc2));
|
||||
(work, fps(&ahead))
|
||||
})
|
||||
.join()
|
||||
.unwrap();
|
||||
assert_eq!(work, 0, "features written out again");
|
||||
assert_eq!(ahead_fps, fps(&window));
|
||||
}
|
||||
|
||||
/// A 10 mm square plate per hole along X, 4 mm thick, in component `comp`, with `holes` square
|
||||
/// holes cut through it by boxes drawn in component `tools` (the plate's own, usually). The
|
||||
/// plate's body name.
|
||||
@@ -647,3 +789,65 @@ fn shared_evaluation_refreshes_live_sketches_and_keeps_unknown_features_conserva
|
||||
assert!(model.results.iter().all(|r| r.error.is_none()));
|
||||
assert!(model.evaluate_shared(&doc), "an unclassified feature must keep the ordinary evaluation path");
|
||||
}
|
||||
|
||||
/// A saved model writes each set of sketch keys once, as the keys it sets and drops relative to
|
||||
/// the set written before it (every state repeating its whole set made a 5,484-feature design's
|
||||
/// model too large for its file, which then kept only some states and evaluated the rest on
|
||||
/// opening). Every state reads back the keys it was evaluated with, also in a model thinned to
|
||||
/// fewer states; a set that names no set before it is refused.
|
||||
#[test]
|
||||
fn saved_states_read_back_their_sketch_keys() {
|
||||
let mut doc = Document::new("Sketch keys");
|
||||
for i in 0..4 {
|
||||
doc.add_feature(line_sketch(PlaneRef::Origin { name: "XY".into() }, Vec2::new(f64::from(i) + 1.0, 1.0)), None).unwrap();
|
||||
for j in 0..3 {
|
||||
let corner = point_expr(Vec3::new(f64::from(i) * 20.0, f64::from(j) * 20.0, 0.0));
|
||||
let kind = FeatureKind::Box { corner, length: "5".into(), width: "5".into(), height: "5".into(), operation: Operation::NewBody };
|
||||
doc.add_feature(kind, None).unwrap();
|
||||
}
|
||||
}
|
||||
let mut model = Model::new();
|
||||
model.evaluate(&doc);
|
||||
let keys = |m: &Model| m.results.iter().map(|r| r.state.sketch_keys.clone()).collect::<Vec<_>>();
|
||||
assert_eq!(model.state().sketch_keys.len(), 4);
|
||||
let saved = model.saved(&doc).unwrap();
|
||||
assert_eq!(saved.records["sketch_key_sets"].as_array().unwrap().len(), 4, "one set per sketch");
|
||||
assert_eq!(saved.records["states"].as_array().unwrap().len(), doc.features.len());
|
||||
assert_eq!(keys(&Model::adopt(&doc, &saved).unwrap()), keys(&model));
|
||||
// The final state alone (every body costs more than the budget): the sets are all kept.
|
||||
let pieces: Vec<Vec<(usize, usize)>> = (0..saved.bodies.len()).map(|i| vec![(i, 1 << 20)]).collect();
|
||||
let (thinned, _, _) = saved.thinned(&pieces, 0).unwrap();
|
||||
assert_eq!(thinned.records["states"].as_array().unwrap().len(), 1);
|
||||
assert_eq!(thinned.final_state().unwrap().sketch_keys, model.state().sketch_keys);
|
||||
assert_eq!(keys(&Model::adopt(&doc, &thinned).unwrap()), keys(&model));
|
||||
// Sets and drops read as written; a base that is not an earlier set is refused.
|
||||
let with_sets = |sets: serde_json::Value| SavedModel {
|
||||
records: {
|
||||
let mut r = saved.records.clone();
|
||||
r["sketch_key_sets"] = sets;
|
||||
r
|
||||
},
|
||||
bodies: saved.bodies.clone(),
|
||||
};
|
||||
let first = *model.state().sketch_keys.keys().next().unwrap();
|
||||
let dropped = with_sets(serde_json::json!([
|
||||
{"set": [[first, "0000000000000001"], [7, "0000000000000002"]], "drop": []},
|
||||
{"base": 0, "set": [], "drop": []},
|
||||
{"base": 1, "set": [[8, "0000000000000003"]], "drop": [first]},
|
||||
{"base": 0, "set": [[7, "00000000000000ff"]], "drop": []},
|
||||
]));
|
||||
let want: BTreeMap<u64, u64> = [(7, 0xff), (first, 1)].into();
|
||||
assert_eq!(dropped.final_state().unwrap().sketch_keys, want);
|
||||
let dropped = with_sets(serde_json::json!([
|
||||
{"set": [[first, "0000000000000001"], [7, "0000000000000002"]], "drop": []},
|
||||
{"base": 0, "set": [], "drop": []},
|
||||
{"base": 0, "set": [], "drop": []},
|
||||
{"base": 1, "set": [[8, "0000000000000003"]], "drop": [first]},
|
||||
]));
|
||||
assert_eq!(dropped.final_state().unwrap().sketch_keys, [(7, 2), (8, 3)].into());
|
||||
for base in [3, 4] {
|
||||
let sets =
|
||||
serde_json::json!([{"set": [], "drop": []}, {"set": [], "drop": []}, {"set": [], "drop": []}, {"base": base, "set": [], "drop": []}]);
|
||||
assert!(with_sets(sets).final_state().is_err(), "base {base}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ pub(super) fn eval(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
FeatureKind::Align { bodies, from, to, from_normal, to_normal, flip, from_plane, to_plane } => {
|
||||
FeatureKind::Align { bodies, from, to, from_normal, to_normal, flip, from_plane, to_plane, axes } => {
|
||||
// A plane on either side is worked out now, so the bodies follow it when it moves.
|
||||
let (mut from, mut from_normal) = (from.0, from_normal.and_then(|n| n.normalized()));
|
||||
if let Some(p) = from_plane {
|
||||
@@ -126,6 +126,28 @@ pub(super) fn eval(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature,
|
||||
(Some(_), Some(n)) => n * (to - from).dot(n),
|
||||
_ => to - from,
|
||||
};
|
||||
// Point-to-point alignment can keep only the chosen world X/Y/Z directions,
|
||||
// stored in the bodies' frame. A missing list means all three (the full offset).
|
||||
let d = match axes {
|
||||
None => d,
|
||||
Some(dirs) if dirs.is_empty() => {
|
||||
return Err(DocError::Invalid("the align axes enable none of X, Y and Z".into()));
|
||||
}
|
||||
Some(dirs) => {
|
||||
let mut kept = Vec3::ZERO;
|
||||
let mut used = false;
|
||||
for a in dirs {
|
||||
if let Some(a) = a.0.normalized() {
|
||||
kept += a * d.dot(a);
|
||||
used = true;
|
||||
}
|
||||
}
|
||||
if !used {
|
||||
return Err(DocError::Invalid("the align axes have no direction".into()));
|
||||
}
|
||||
kept
|
||||
}
|
||||
};
|
||||
m[3][0] += d.x;
|
||||
m[3][1] += d.y;
|
||||
m[3][2] += d.z;
|
||||
@@ -821,12 +843,12 @@ pub(super) fn sheet_eval(
|
||||
// (its outer level, `hi`) with z into the material, as with bend edges, so the sheet
|
||||
// takes the plate's place: its thickness runs from `hi` back to `lo`.
|
||||
let plane = Plane::from_normal(face.0 + n * hi, n * -1.0).ok_or_else(|| DocError::Invalid("face".into()))?;
|
||||
let slice = FaceSlice { mesh: &mesh, plane, at: face.0, n, tol };
|
||||
// Recesses in one face (an engraved label) become pockets; the outline is the other face's.
|
||||
let recesses = plate_recesses(&mb.body, &mesh, &plane, face.0, n, (lo, hi), tol)?;
|
||||
let recesses = slice.recesses(&mb.body, (lo, hi))?;
|
||||
let mut walls = std::collections::HashMap::new();
|
||||
let mut wall = |f: u32| *walls.entry(f).or_insert_with(|| sheet::round_wall(&mb.body, &plane, n, f));
|
||||
let mut loops: Vec<Loop2> =
|
||||
face_outline(&mesh, &plane, face.0, n, recesses.level, tol).iter().map(|l| sheet::outline_loop(l, &mut wall, tol * 1e-2)).collect();
|
||||
let mut loops: Vec<Loop2> = slice.outline(recesses.level).iter().map(|l| sheet::outline_loop(l, &mut wall, tol * 1e-2)).collect();
|
||||
loops.sort_by(|a, b| b.signed_area().abs().total_cmp(&a.signed_area().abs()));
|
||||
let mut it = loops.into_iter();
|
||||
let outer = it.next().ok_or_else(|| DocError::Invalid("no outline on that face".into()))?.ccw();
|
||||
@@ -1584,43 +1606,58 @@ fn parted_note(sh: &sheet::SheetBody, material: &[Region2], before: &sheet::Shee
|
||||
})
|
||||
}
|
||||
|
||||
/// Outline loops (in `plane` coordinates) of the mesh triangles lying in the plane at distance
|
||||
/// `level` from `at` along `n`: the edges used by one of them only, chained.
|
||||
fn face_loops(mesh: &solidcraft_geom::Mesh, plane: &Plane, at: Vec3, n: Vec3, level: f64, tol: f64) -> Vec<Ring<Vec2>> {
|
||||
face_outline(mesh, plane, at, n, level, tol).into_iter().map(|l| l.into_iter().map(|(p, _)| p).collect()).collect()
|
||||
/// The face that [`FaceSlice::loops`], [`FaceSlice::outline`] and [`FaceSlice::recesses`] measure:
|
||||
/// the mesh, the plane the outline's coordinates live in, the point `at` and normal `n` that levels
|
||||
/// are measured from, and the tolerance. Callers build it once and pass it on unchanged.
|
||||
/// (`n` stays a `Vec3` until #2675 lands `UnitVec3` upstream.)
|
||||
struct FaceSlice<'a> {
|
||||
mesh: &'a Mesh,
|
||||
plane: Plane,
|
||||
at: Vec3,
|
||||
n: Vec3,
|
||||
tol: f64,
|
||||
}
|
||||
|
||||
/// [`face_loops`] with each point's B-rep face across the outline from it to the next point (the
|
||||
/// wall the outline runs along there): the face off the plane that meets both points.
|
||||
fn face_outline(mesh: &solidcraft_geom::Mesh, plane: &Plane, at: Vec3, n: Vec3, level: f64, tol: f64) -> Vec<Vec<(Vec2, Option<u32>)>> {
|
||||
let on_plane = |t: &[u32; 3]| t.iter().all(|k| mesh.positions.get(*k as usize).is_some_and(|p| ((*p - at).dot(n) - level).abs() < tol));
|
||||
let on: Vec<[u32; 3]> = mesh.triangles.iter().copied().filter(on_plane).collect();
|
||||
let pos = |k: u32| mesh.positions.get(k as usize).copied().unwrap_or_default();
|
||||
let q = |p: Vec3| ((p.x * 1e6).round() as i64, (p.y * 1e6).round() as i64, (p.z * 1e6).round() as i64);
|
||||
// The faces off the plane at each point on it, by position to a millionth of a millimetre
|
||||
// either way (a neighbouring face's mesh may round a shared point differently).
|
||||
let mut touch: std::collections::HashMap<(i64, i64, i64), Vec<u32>> = Default::default();
|
||||
for (t, f) in mesh.triangles.iter().zip(&mesh.tri_face).filter(|(t, _)| !on_plane(t)) {
|
||||
for p in t.iter().map(|k| pos(*k)).filter(|p| ((*p - at).dot(n) - level).abs() < tol) {
|
||||
let faces = touch.entry(q(p)).or_default();
|
||||
if !faces.contains(f) {
|
||||
faces.push(*f);
|
||||
impl FaceSlice<'_> {
|
||||
/// Outline loops (in `plane` coordinates) of the mesh triangles lying in the plane at distance
|
||||
/// `level` from `at` along `n`: the edges used by one of them only, chained.
|
||||
fn loops(&self, level: f64) -> Vec<Ring<Vec2>> {
|
||||
self.outline(level).into_iter().map(|l| l.into_iter().map(|(p, _)| p).collect()).collect()
|
||||
}
|
||||
|
||||
/// [`FaceSlice::loops`] with each point's B-rep face across the outline from it to the next
|
||||
/// point (the wall the outline runs along there): the face off the plane that meets both points.
|
||||
fn outline(&self, level: f64) -> Vec<Vec<(Vec2, Option<u32>)>> {
|
||||
let (mesh, plane, at, n, tol) = (self.mesh, &self.plane, self.at, self.n, self.tol);
|
||||
let on_plane = |t: &[u32; 3]| t.iter().all(|k| mesh.positions.get(*k as usize).is_some_and(|p| ((*p - at).dot(n) - level).abs() < tol));
|
||||
let on: Vec<[u32; 3]> = mesh.triangles.iter().copied().filter(on_plane).collect();
|
||||
let pos = |k: u32| mesh.positions.get(k as usize).copied().unwrap_or_default();
|
||||
let q = |p: Vec3| ((p.x * 1e6).round() as i64, (p.y * 1e6).round() as i64, (p.z * 1e6).round() as i64);
|
||||
// The faces off the plane at each point on it, by position to a millionth of a millimetre
|
||||
// either way (a neighbouring face's mesh may round a shared point differently).
|
||||
let mut touch: std::collections::HashMap<(i64, i64, i64), Vec<u32>> = Default::default();
|
||||
for (t, f) in mesh.triangles.iter().zip(&mesh.tri_face).filter(|(t, _)| !on_plane(t)) {
|
||||
for p in t.iter().map(|k| pos(*k)).filter(|p| ((*p - at).dot(n) - level).abs() < tol) {
|
||||
let faces = touch.entry(q(p)).or_default();
|
||||
if !faces.contains(f) {
|
||||
faces.push(*f);
|
||||
}
|
||||
}
|
||||
}
|
||||
let near = |p: Vec3| {
|
||||
let (x, y, z) = q(p);
|
||||
let cells = (-1..=1).flat_map(|i| (-1..=1).flat_map(move |j| (-1..=1).map(move |k| (x + i, y + j, z + k))));
|
||||
let mut faces: Vec<u32> = cells.filter_map(|c| touch.get(&c)).flatten().copied().collect();
|
||||
faces.sort_unstable();
|
||||
faces.dedup();
|
||||
faces
|
||||
};
|
||||
let across = |a: Vec3, b: Vec3| {
|
||||
let at_b = near(b);
|
||||
near(a).into_iter().find(|f| at_b.contains(f))
|
||||
};
|
||||
chain_loops(mesh, plane, &on, across)
|
||||
}
|
||||
let near = |p: Vec3| {
|
||||
let (x, y, z) = q(p);
|
||||
let cells = (-1..=1).flat_map(|i| (-1..=1).flat_map(move |j| (-1..=1).map(move |k| (x + i, y + j, z + k))));
|
||||
let mut faces: Vec<u32> = cells.filter_map(|c| touch.get(&c)).flatten().copied().collect();
|
||||
faces.sort_unstable();
|
||||
faces.dedup();
|
||||
faces
|
||||
};
|
||||
let across = |a: Vec3, b: Vec3| {
|
||||
let at_b = near(b);
|
||||
near(a).into_iter().find(|f| at_b.contains(f))
|
||||
};
|
||||
chain_loops(mesh, plane, &on, across)
|
||||
}
|
||||
|
||||
/// The loops (in `plane` coordinates) that bound the triangles `on` of the mesh.
|
||||
@@ -1710,138 +1747,142 @@ struct LevelFace {
|
||||
tris: Vec<(Vec3, f64)>,
|
||||
}
|
||||
|
||||
/// The recesses of a plate lying between levels `lo` and `hi` along `n` (measured from `at`),
|
||||
/// whose sheet is built in `plane`. A recess's floor is a face parallel to the plate inside its
|
||||
/// thickness, lying in an opening of the face it is cut into, and its walls are square to the
|
||||
/// plate (walls that are not show as material the plate's volume doesn't account for). A body
|
||||
/// that is no plate once its recesses are filled has none, so the plate check refuses it as
|
||||
/// before: a bent part, whose legs' faces lie inside its extent. Recesses are taken in one face
|
||||
/// only, up to half the thickness deep, and no larger than the face they are cut into (a plate
|
||||
/// raised in places is no plate of the raised thickness).
|
||||
fn plate_recesses(body: &Body, mesh: &Mesh, plane: &Plane, at: Vec3, n: Vec3, (lo, hi): (f64, f64), tol: f64) -> Result<Recesses> {
|
||||
let t = hi - lo;
|
||||
let eps = t * 1e-3;
|
||||
let level = |p: Vec3| (p - at).dot(n);
|
||||
let mut faces: BTreeMap<u32, Option<LevelFace>> = BTreeMap::new();
|
||||
for (tri, f) in mesh.triangles.iter().zip(&mesh.tri_face) {
|
||||
let Some([a, b, c]) = mesh.tri(tri) else { continue };
|
||||
let cr = (b - a).cross(c - a);
|
||||
let len = cr.len();
|
||||
if !(len > 1e-12) {
|
||||
continue;
|
||||
}
|
||||
let up = cr.dot(n) > 0.0;
|
||||
let entry = faces.entry(*f).or_insert(Some(LevelFace { lo: f64::MAX, hi: f64::MIN, up, area: 0.0, at: a, tris: Vec::new() }));
|
||||
match entry {
|
||||
Some(face) if face.up == up && cr.dot(n).abs() >= len * (1.0 - 1e-6) => {
|
||||
for p in [a, b, c] {
|
||||
face.lo = face.lo.min(level(p));
|
||||
face.hi = face.hi.max(level(p));
|
||||
}
|
||||
face.area += len / 2.0;
|
||||
face.tris.push(((a + b + c) / 3.0, len / 2.0));
|
||||
impl FaceSlice<'_> {
|
||||
/// The recesses of a plate lying between levels `lo` and `hi` along `n` (measured from `at`),
|
||||
/// whose sheet is built in `plane`. A recess's floor is a face parallel to the plate inside its
|
||||
/// thickness, lying in an opening of the face it is cut into, and its walls are square to the
|
||||
/// plate (walls that are not show as material the plate's volume doesn't account for). A body
|
||||
/// that is no plate once its recesses are filled has none, so the plate check refuses it as
|
||||
/// before: a bent part, whose legs' faces lie inside its extent. Recesses are taken in one face
|
||||
/// only, up to half the thickness deep, and no larger than the face they are cut into (a plate
|
||||
/// raised in places is no plate of the raised thickness).
|
||||
fn recesses(&self, body: &Body, (lo, hi): (f64, f64)) -> Result<Recesses> {
|
||||
let (mesh, plane, at, n, tol) = (self.mesh, &self.plane, self.at, self.n, self.tol);
|
||||
let t = hi - lo;
|
||||
let eps = t * 1e-3;
|
||||
let level = |p: Vec3| (p - at).dot(n);
|
||||
let mut faces: BTreeMap<u32, Option<LevelFace>> = BTreeMap::new();
|
||||
for (tri, f) in mesh.triangles.iter().zip(&mesh.tri_face) {
|
||||
let Some([a, b, c]) = mesh.tri(tri) else { continue };
|
||||
let cr = (b - a).cross(c - a);
|
||||
let len = cr.len();
|
||||
if !(len > 1e-12) {
|
||||
continue;
|
||||
}
|
||||
let up = cr.dot(n) > 0.0;
|
||||
let entry = faces.entry(*f).or_insert(Some(LevelFace { lo: f64::MAX, hi: f64::MIN, up, area: 0.0, at: a, tris: Vec::new() }));
|
||||
match entry {
|
||||
Some(face) if face.up == up && cr.dot(n).abs() >= len * (1.0 - 1e-6) => {
|
||||
for p in [a, b, c] {
|
||||
face.lo = face.lo.min(level(p));
|
||||
face.hi = face.hi.max(level(p));
|
||||
}
|
||||
face.area += len / 2.0;
|
||||
face.tris.push(((a + b + c) / 3.0, len / 2.0));
|
||||
}
|
||||
_ => *entry = None,
|
||||
}
|
||||
_ => *entry = None,
|
||||
}
|
||||
}
|
||||
// The floors (face index, level, the face), and the areas of the plate's two faces (at `lo`
|
||||
// and at `hi`).
|
||||
let mut floors: Vec<(usize, f64, &LevelFace)> = Vec::new();
|
||||
let (mut bottom, mut top) = (0.0, 0.0);
|
||||
for (f, face) in faces.iter().filter_map(|(f, face)| Some((*f as usize, face.as_ref()?))) {
|
||||
let d = (face.lo + face.hi) / 2.0;
|
||||
if face.hi - face.lo > eps {
|
||||
continue;
|
||||
} else if (d - hi).abs() <= eps && face.up {
|
||||
top += face.area;
|
||||
} else if (d - lo).abs() <= eps && !face.up {
|
||||
bottom += face.area;
|
||||
} else if d > lo + eps && d < hi - eps {
|
||||
floors.push((f, d, face));
|
||||
// The floors (face index, level, the face), and the areas of the plate's two faces (at `lo`
|
||||
// and at `hi`).
|
||||
let mut floors: Vec<(usize, f64, &LevelFace)> = Vec::new();
|
||||
let (mut bottom, mut top) = (0.0, 0.0);
|
||||
for (f, face) in faces.iter().filter_map(|(f, face)| Some((*f as usize, face.as_ref()?))) {
|
||||
let d = (face.lo + face.hi) / 2.0;
|
||||
if face.hi - face.lo > eps {
|
||||
continue;
|
||||
} else if (d - hi).abs() <= eps && face.up {
|
||||
top += face.area;
|
||||
} else if (d - lo).abs() <= eps && !face.up {
|
||||
bottom += face.area;
|
||||
} else if d > lo + eps && d < hi - eps {
|
||||
floors.push((f, d, face));
|
||||
}
|
||||
}
|
||||
}
|
||||
let none = || Recesses { level: lo, pockets: Vec::new(), volume: 0.0 };
|
||||
if floors.is_empty() {
|
||||
return Ok(none());
|
||||
}
|
||||
// A floor is a recess's where (most of) it lies in an opening of the face it is cut into:
|
||||
// inside that face's outline and in a hole of it, not on an island in the hole. (Its
|
||||
// triangles are those at its level within `eps`: `tol` may exceed a recess's depth.)
|
||||
let loops_at = |level: f64| -> Vec<Loop2> { face_loops(mesh, plane, at, n, level, eps).into_iter().map(|l| Loop2::polygon(&l)).collect() };
|
||||
let (top_loops, bottom_loops) = (loops_at(hi), loops_at(lo));
|
||||
floors.retain(|(_, _, face)| {
|
||||
let loops = if face.up { &top_loops } else { &bottom_loops };
|
||||
let open = |p: Vec2| {
|
||||
let k = loops.iter().filter(|l| l.contains(p)).count();
|
||||
k >= 2 && k.is_multiple_of(2)
|
||||
};
|
||||
face.tris.iter().filter(|(c, _)| open(plane.to_local(*c))).map(|(_, a)| a).sum::<f64>() > face.area / 2.0
|
||||
});
|
||||
let Some(&(_, _, first)) = floors.first() else { return Ok(none()) };
|
||||
// Filled, the recesses leave a plate: its outline as large at `lo` as at `hi` once their
|
||||
// openings count, and its volume with theirs the outline times the thickness. Else (a bent
|
||||
// part) they are none.
|
||||
let depth_in = |d: f64, up: bool| if up { hi - d } else { d - lo };
|
||||
let opened = |up: bool| floors.iter().filter(|f| f.2.up == up).map(|f| f.2.area).sum::<f64>();
|
||||
let outline = bottom + opened(false);
|
||||
let removed: f64 = floors.iter().map(|f| f.2.area * depth_in(f.1, f.2.up)).sum();
|
||||
let volume = kernel::measure(body)?.volume;
|
||||
if (outline - top - opened(true)).abs() > 1e-3 * outline || (outline * t - volume - removed).abs() > 1e-3 * volume.max(1.0) {
|
||||
return Ok(none());
|
||||
}
|
||||
let pt = |p: Vec3| format!("({:.3}, {:.3}, {:.3})", p.x, p.y, p.z);
|
||||
let up = first.up;
|
||||
if let Some(other) = floors.iter().find(|f| f.2.up != up) {
|
||||
return Err(DocError::Invalid(format!(
|
||||
"not supported yet: converting a plate with recesses in both faces (at {} and {}); recesses in one face become pockets",
|
||||
pt(first.at),
|
||||
pt(other.2.at)
|
||||
)));
|
||||
}
|
||||
let depth_of = |d: f64| depth_in(d, up);
|
||||
if let Some(deep) = floors.iter().find(|f| depth_of(f.1) > t / 2.0 + eps) {
|
||||
return Err(DocError::Invalid(format!(
|
||||
"not supported yet: the recess at {} is {:.3} mm deep, more than half the plate's {:.3} mm; shallower recesses (an engraving, a label) become pockets",
|
||||
pt(deep.2.at),
|
||||
depth_of(deep.1),
|
||||
t
|
||||
)));
|
||||
}
|
||||
let face_area = if up { top } else { bottom };
|
||||
if floors.iter().map(|f| f.2.area).sum::<f64>() > face_area {
|
||||
return Err(DocError::Invalid(format!(
|
||||
"not supported yet: converting a plate whose recesses are larger than the face they are in (a plate thinner than {t:.3} mm, raised in places)"
|
||||
)));
|
||||
}
|
||||
// The floors' outlines, from a mesh fine enough to mark them by.
|
||||
let fine = body.tessellate((t * 1e-2).min(tol).max(1e-4))?;
|
||||
floors.sort_by(|a, b| depth_of(a.1).total_cmp(&depth_of(b.1)));
|
||||
// Floors at one depth are one pocket where they meet.
|
||||
let mut groups: Vec<(f64, Vec<Region2>)> = Vec::new();
|
||||
for (f, d, ..) in &floors {
|
||||
let on: Vec<[u32; 3]> = fine.triangles.iter().zip(&fine.tri_face).filter(|(_, g)| **g as usize == *f).map(|(tri, _)| *tri).collect();
|
||||
let mut loops = boundary_loops(&fine, plane, &on);
|
||||
loops.sort_by(|a, b| b.signed_area().abs().total_cmp(&a.signed_area().abs()));
|
||||
let mut it = loops.into_iter();
|
||||
let Some(outline) = it.next() else { continue };
|
||||
let region = Region2 { outer: Loop2::polygon(&outline).ccw(), holes: it.map(|l| Loop2::polygon(&l).ccw().reversed()).collect() };
|
||||
match groups.last_mut() {
|
||||
Some((depth, regions)) if depth_of(*d) - *depth <= eps => regions.push(region),
|
||||
_ => groups.push((depth_of(*d), vec![region])),
|
||||
let none = || Recesses { level: lo, pockets: Vec::new(), volume: 0.0 };
|
||||
if floors.is_empty() {
|
||||
return Ok(none());
|
||||
}
|
||||
}
|
||||
// The sheet's z starts from the picked face when its plane faces away from that face.
|
||||
let from_zero = up == (plane.normal().dot(n) < 0.0);
|
||||
let mut work = sheet::FlatWork::new();
|
||||
let (mut pockets, mut volume) = (Vec::new(), 0.0);
|
||||
for (depth, regions) in groups {
|
||||
let (z0, z1) = if from_zero { (0.0, depth) } else { (t - depth, t) };
|
||||
for region in sheet::material_union(regions, &mut work)? {
|
||||
volume += region.area().abs() * depth;
|
||||
pockets.push((region, z0, z1));
|
||||
// A floor is a recess's where (most of) it lies in an opening of the face it is cut into:
|
||||
// inside that face's outline and in a hole of it, not on an island in the hole. (Its
|
||||
// triangles are those at its level within `eps`: `tol` may exceed a recess's depth.)
|
||||
let probe = FaceSlice { mesh, plane: self.plane, at, n, tol: eps };
|
||||
let loops_at = |level: f64| -> Vec<Loop2> { probe.loops(level).into_iter().map(|l| Loop2::polygon(&l)).collect() };
|
||||
let (top_loops, bottom_loops) = (loops_at(hi), loops_at(lo));
|
||||
floors.retain(|(_, _, face)| {
|
||||
let loops = if face.up { &top_loops } else { &bottom_loops };
|
||||
let open = |p: Vec2| {
|
||||
let k = loops.iter().filter(|l| l.contains(p)).count();
|
||||
k >= 2 && k.is_multiple_of(2)
|
||||
};
|
||||
face.tris.iter().filter(|(c, _)| open(plane.to_local(*c))).map(|(_, a)| a).sum::<f64>() > face.area / 2.0
|
||||
});
|
||||
let Some(&(_, _, first)) = floors.first() else { return Ok(none()) };
|
||||
// Filled, the recesses leave a plate: its outline as large at `lo` as at `hi` once their
|
||||
// openings count, and its volume with theirs the outline times the thickness. Else (a bent
|
||||
// part) they are none.
|
||||
let depth_in = |d: f64, up: bool| if up { hi - d } else { d - lo };
|
||||
let opened = |up: bool| floors.iter().filter(|f| f.2.up == up).map(|f| f.2.area).sum::<f64>();
|
||||
let outline = bottom + opened(false);
|
||||
let removed: f64 = floors.iter().map(|f| f.2.area * depth_in(f.1, f.2.up)).sum();
|
||||
let volume = kernel::measure(body)?.volume;
|
||||
if (outline - top - opened(true)).abs() > 1e-3 * outline || (outline * t - volume - removed).abs() > 1e-3 * volume.max(1.0) {
|
||||
return Ok(none());
|
||||
}
|
||||
let pt = |p: Vec3| format!("({:.3}, {:.3}, {:.3})", p.x, p.y, p.z);
|
||||
let up = first.up;
|
||||
if let Some(other) = floors.iter().find(|f| f.2.up != up) {
|
||||
return Err(DocError::Invalid(format!(
|
||||
"not supported yet: converting a plate with recesses in both faces (at {} and {}); recesses in one face become pockets",
|
||||
pt(first.at),
|
||||
pt(other.2.at)
|
||||
)));
|
||||
}
|
||||
let depth_of = |d: f64| depth_in(d, up);
|
||||
if let Some(deep) = floors.iter().find(|f| depth_of(f.1) > t / 2.0 + eps) {
|
||||
return Err(DocError::Invalid(format!(
|
||||
"not supported yet: the recess at {} is {:.3} mm deep, more than half the plate's {:.3} mm; shallower recesses (an engraving, a label) become pockets",
|
||||
pt(deep.2.at),
|
||||
depth_of(deep.1),
|
||||
t
|
||||
)));
|
||||
}
|
||||
let face_area = if up { top } else { bottom };
|
||||
if floors.iter().map(|f| f.2.area).sum::<f64>() > face_area {
|
||||
return Err(DocError::Invalid(format!(
|
||||
"not supported yet: converting a plate whose recesses are larger than the face they are in (a plate thinner than {t:.3} mm, raised in places)"
|
||||
)));
|
||||
}
|
||||
// The floors' outlines, from a mesh fine enough to mark them by.
|
||||
let fine = body.tessellate((t * 1e-2).min(tol).max(1e-4))?;
|
||||
floors.sort_by(|a, b| depth_of(a.1).total_cmp(&depth_of(b.1)));
|
||||
// Floors at one depth are one pocket where they meet.
|
||||
let mut groups: Vec<(f64, Vec<Region2>)> = Vec::new();
|
||||
for (f, d, ..) in &floors {
|
||||
let on: Vec<[u32; 3]> = fine.triangles.iter().zip(&fine.tri_face).filter(|(_, g)| **g as usize == *f).map(|(tri, _)| *tri).collect();
|
||||
let mut loops = boundary_loops(&fine, plane, &on);
|
||||
loops.sort_by(|a, b| b.signed_area().abs().total_cmp(&a.signed_area().abs()));
|
||||
let mut it = loops.into_iter();
|
||||
let Some(outline) = it.next() else { continue };
|
||||
let region = Region2 { outer: Loop2::polygon(&outline).ccw(), holes: it.map(|l| Loop2::polygon(&l).ccw().reversed()).collect() };
|
||||
match groups.last_mut() {
|
||||
Some((depth, regions)) if depth_of(*d) - *depth <= eps => regions.push(region),
|
||||
_ => groups.push((depth_of(*d), vec![region])),
|
||||
}
|
||||
}
|
||||
// The sheet's z starts from the picked face when its plane faces away from that face.
|
||||
let from_zero = up == (plane.normal().dot(n) < 0.0);
|
||||
let mut work = sheet::FlatWork::new();
|
||||
let (mut pockets, mut volume) = (Vec::new(), 0.0);
|
||||
for (depth, regions) in groups {
|
||||
let (z0, z1) = if from_zero { (0.0, depth) } else { (t - depth, t) };
|
||||
for region in sheet::material_union(regions, &mut work)? {
|
||||
volume += region.area().abs() * depth;
|
||||
pockets.push((region, z0, z1));
|
||||
}
|
||||
}
|
||||
Ok(Recesses { level: if up { lo } else { hi }, pockets, volume })
|
||||
}
|
||||
Ok(Recesses { level: if up { lo } else { hi }, pockets, volume })
|
||||
}
|
||||
|
||||
/// The body a placed plastic feature joins: by name, else the one under the point.
|
||||
@@ -2033,7 +2074,8 @@ pub(super) fn plastic_eval(doc: &Document, vals: &BTreeMap<String, Value>, f: &F
|
||||
let plane = Plane::from_normal(face.0, n).ok_or_else(|| DocError::Invalid("rim plane".into()))?;
|
||||
let tol = (mb.body.size() * 1e-3).max(1e-3);
|
||||
let mesh = mb.body.tessellate(tol)?;
|
||||
let mut loops = face_loops(&mesh, &plane, face.0, n, 0.0, tol);
|
||||
let slice = FaceSlice { mesh: &mesh, plane, at: face.0, n, tol };
|
||||
let mut loops = slice.loops(0.0);
|
||||
loops.sort_by(|a, b| b.signed_area().abs().total_cmp(&a.signed_area().abs()));
|
||||
let ccw = |l: &Ring<Vec2>| if l.signed_area() < 0.0 { l.iter().rev().copied().collect::<Ring<_>>() } else { l.clone() };
|
||||
// The inner edge is an opening (the cavity under a rim): not the foot of a boss or a
|
||||
|
||||
@@ -161,6 +161,12 @@ pub const FUNCTIONS: &[(&str, &str)] = &[
|
||||
("ceil", "ceil(x)"),
|
||||
("round", "round(x)"),
|
||||
("exp", "exp(x)"),
|
||||
("sinh", "sinh(x)"),
|
||||
("cosh", "cosh(x)"),
|
||||
("tanh", "tanh(x)"),
|
||||
("asinh", "asinh(x)"),
|
||||
("acosh", "acosh(x), x ≥ 1"),
|
||||
("atanh", "atanh(x), −1 < x < 1"),
|
||||
("ln", "ln(x)"),
|
||||
("log", "log(x) (base 10)"),
|
||||
("log10", "log10(x)"),
|
||||
@@ -344,8 +350,9 @@ fn lex_spans(s: &str) -> Result<Vec<(Tok, usize, usize)>, DocError> {
|
||||
let at = |i: usize| cs.get(i).map(|x| x.0).unwrap_or(s.len());
|
||||
let mut i = 0;
|
||||
let mut out = Vec::new();
|
||||
// Parentheses open at this point: a comma outside them can only be a decimal comma.
|
||||
let mut depth = 0usize;
|
||||
// Parentheses open at this point, innermost last, true for a function call's: a comma directly
|
||||
// in a call separates its arguments, and anywhere else can only be a decimal comma (#9408).
|
||||
let mut parens: Vec<bool> = Vec::new();
|
||||
// A single leading `=` marks the text as a formula (`=d3`, #4681) and is not part of it.
|
||||
if let Some(k) = cs.iter().position(|(_, c)| !c.is_whitespace())
|
||||
&& cs.get(k).is_some_and(|(_, c)| *c == '=')
|
||||
@@ -363,7 +370,7 @@ fn lex_spans(s: &str) -> Result<Vec<(Tok, usize, usize)>, DocError> {
|
||||
while let Some(&(_, c)) = cs.get(i) {
|
||||
if c.is_whitespace() {
|
||||
i += 1;
|
||||
} else if c.is_ascii_digit() || c == '.' || leading_decimal_comma(&cs, i, depth, out.last()) {
|
||||
} else if c.is_ascii_digit() || c == '.' || leading_decimal_comma(&cs, i, in_call(&parens), out.last()) {
|
||||
let st = i;
|
||||
// A leading decimal comma (`,5` for 0,5, #2966) starts the number as `.5` would.
|
||||
let leading_comma = c == ',';
|
||||
@@ -374,11 +381,17 @@ fn lex_spans(s: &str) -> Result<Vec<(Tok, usize, usize)>, DocError> {
|
||||
i += 1;
|
||||
}
|
||||
// A decimal comma (`2,5 mm`, as typed with a numeric keypad in many locales, #1347):
|
||||
// a comma between digits, in a number with no point, outside any parentheses (inside
|
||||
// them a comma separates a function's arguments: `max(1,2)`).
|
||||
// a comma between digits, in a number with no point, not directly in a function call
|
||||
// (there a comma separates arguments: `max(1,2)`).
|
||||
let digit = |k: usize| cs.get(k).is_some_and(|(_, c)| c.is_ascii_digit());
|
||||
let has_point = cs.get(st..i).is_some_and(|ds| ds.iter().any(|(_, c)| *c == '.'));
|
||||
if depth == 0 && !leading_comma && !has_point && digit(i.wrapping_sub(1)) && cs.get(i).is_some_and(|(_, c)| *c == ',') && digit(i + 1) {
|
||||
if !in_call(&parens)
|
||||
&& !leading_comma
|
||||
&& !has_point
|
||||
&& digit(i.wrapping_sub(1))
|
||||
&& cs.get(i).is_some_and(|(_, c)| *c == ',')
|
||||
&& digit(i + 1)
|
||||
{
|
||||
i += 1;
|
||||
while digit(i) {
|
||||
i += 1;
|
||||
@@ -400,7 +413,7 @@ fn lex_spans(s: &str) -> Result<Vec<(Tok, usize, usize)>, DocError> {
|
||||
// A mixed number, as imperial sizes are written (`2 1/8"` is 2.125 in, #1802): a whole
|
||||
// number, then a proper fraction of whole numbers, is one value, not `2 × 1/8`.
|
||||
if t.chars().all(|c| c.is_ascii_digit())
|
||||
&& let Some((fraction, end)) = mixed_fraction(&cs, i, depth)
|
||||
&& let Some((fraction, end)) = mixed_fraction(&cs, i, in_call(&parens))
|
||||
{
|
||||
out.push((Tok::Num(v + fraction), at(st), at(end)));
|
||||
i = end;
|
||||
@@ -438,8 +451,10 @@ fn lex_spans(s: &str) -> Result<Vec<(Tok, usize, usize)>, DocError> {
|
||||
i += 1;
|
||||
} else if "+-*/^(),%".contains(c) {
|
||||
match c {
|
||||
'(' => depth += 1,
|
||||
')' => depth = depth.saturating_sub(1),
|
||||
'(' => parens.push(matches!(out.last(), Some((Tok::Id(_), _, _)))),
|
||||
')' => {
|
||||
parens.pop();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
out.push((Tok::Op(c), at(i), at(i + 1)));
|
||||
@@ -451,27 +466,32 @@ fn lex_spans(s: &str) -> Result<Vec<(Tok, usize, usize)>, DocError> {
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
/// Whether the innermost open parenthesis is a function call's.
|
||||
fn in_call(parens: &[bool]) -> bool {
|
||||
parens.last() == Some(&true)
|
||||
}
|
||||
|
||||
/// Whether the comma at `i` starts a number, as a leading decimal comma (`,5` for 0,5, #2966).
|
||||
/// It must be outside parentheses (inside them a comma separates arguments, as for any decimal
|
||||
/// comma), be followed by a digit, and stand where an operand is expected: at the start or right
|
||||
/// after `+ - * / ^`. A comma after a number, name, `)` or `%` keeps its meaning (`2 ,5` and
|
||||
/// `1,5,3` stay errors).
|
||||
fn leading_decimal_comma(cs: &[(usize, char)], i: usize, depth: usize, prev: Option<&(Tok, usize, usize)>) -> bool {
|
||||
depth == 0
|
||||
/// It must not be directly in a function call (`in_call`: there a comma separates arguments, as
|
||||
/// for any decimal comma), be followed by a digit, and stand where an operand is expected: at the
|
||||
/// start or right after `( + - * / ^`. A comma after a number, name, `)` or `%` keeps its meaning
|
||||
/// (`2 ,5` and `1,5,3` stay errors).
|
||||
fn leading_decimal_comma(cs: &[(usize, char)], i: usize, in_call: bool, prev: Option<&(Tok, usize, usize)>) -> bool {
|
||||
!in_call
|
||||
&& cs.get(i).is_some_and(|(_, c)| *c == ',')
|
||||
&& cs.get(i + 1).is_some_and(|(_, c)| c.is_ascii_digit())
|
||||
&& match prev {
|
||||
None => true,
|
||||
Some((Tok::Op(op), _, _)) => "+-*/^".contains(*op),
|
||||
Some((Tok::Op(op), _, _)) => "(+-*/^".contains(*op),
|
||||
Some(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// The proper fraction of a mixed number whose whole part ends at `i`: spaces, digits, `/`,
|
||||
/// digits, with nothing after them that would continue the number (`2 1/8.5`, `2 1/8e3`, a
|
||||
/// decimal comma outside parentheses: `2 1/8,5`). Its value and where it ends. `depth`: the
|
||||
/// parentheses open there (inside them a comma separates arguments: `max(2 1/8,1)`).
|
||||
fn mixed_fraction(cs: &[(usize, char)], mut i: usize, depth: usize) -> Option<(f64, usize)> {
|
||||
/// decimal comma: `2 1/8,5`). Its value and where it ends. `in_call`: directly in a function call
|
||||
/// there (a comma separates arguments: `max(2 1/8,1)`).
|
||||
fn mixed_fraction(cs: &[(usize, char)], mut i: usize, in_call: bool) -> Option<(f64, usize)> {
|
||||
let digits = |from: usize| cs.get(from..).map_or(0, |rest| rest.iter().take_while(|(_, c)| c.is_ascii_digit()).count());
|
||||
let space = i;
|
||||
while cs.get(i).is_some_and(|(_, c)| *c == ' ' || *c == '\t') {
|
||||
@@ -485,7 +505,7 @@ fn mixed_fraction(cs: &[(usize, char)], mut i: usize, depth: usize) -> Option<(f
|
||||
let end = i + numerator + 1 + denominator;
|
||||
let next = |k: usize| cs.get(end + k).map(|(_, c)| *c);
|
||||
let continues = matches!(next(0), Some('.'))
|
||||
|| (depth == 0 && matches!(next(0), Some(',')) && next(1).is_some_and(|c| c.is_ascii_digit()))
|
||||
|| (!in_call && matches!(next(0), Some(',')) && next(1).is_some_and(|c| c.is_ascii_digit()))
|
||||
|| (matches!(next(0), Some('e' | 'E')) && next(1).is_some_and(|c| c.is_ascii_digit() || c == '-' || c == '+'));
|
||||
if denominator == 0 || continues {
|
||||
return None;
|
||||
@@ -589,9 +609,11 @@ pub fn is_literal(s: &str) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the expression a bare number without a unit, like `20` or `-1.5`?
|
||||
/// Is the expression a bare number without a unit, like `20` or `-1.5`? A leading `=` only marks
|
||||
/// a formula (#4681), so `=20` is the same bare number.
|
||||
pub fn is_bare_number(s: &str) -> bool {
|
||||
is_literal(s) && s.trim().trim_start_matches(['-', '+']).trim().parse::<f64>().is_ok()
|
||||
let number = s.trim().strip_prefix('=').unwrap_or(s);
|
||||
is_literal(s) && number.trim().trim_start_matches(['-', '+']).trim().parse::<f64>().is_ok()
|
||||
}
|
||||
|
||||
/// Is `s` shaped like a parameter name: a letter or `_`, then letters, digits and `_`? The shape
|
||||
@@ -943,6 +965,24 @@ fn call(f: &str, args: &[Value], d: Defaults) -> Result<Value, DocError> {
|
||||
unit_fn(r * if scale != 0.0 { scale } else { 1.0 }, a)
|
||||
}
|
||||
"exp" => Value::num(num(one()?)?.exp()),
|
||||
"sinh" => Value::num(num(one()?)?.sinh()),
|
||||
"cosh" => Value::num(num(one()?)?.cosh()),
|
||||
"tanh" => Value::num(num(one()?)?.tanh()),
|
||||
"asinh" => Value::num(num(one()?)?.asinh()),
|
||||
"acosh" => {
|
||||
let x = num(one()?)?;
|
||||
if !(x >= 1.0) {
|
||||
return Err(DocError::Expr("`acosh` needs a number of at least 1".into()));
|
||||
}
|
||||
Value::num(x.acosh())
|
||||
}
|
||||
"atanh" => {
|
||||
let x = num(one()?)?;
|
||||
if !(x > -1.0 && x < 1.0) {
|
||||
return Err(DocError::Expr("`atanh` needs a number between -1 and 1, both excluded".into()));
|
||||
}
|
||||
Value::num(x.atanh())
|
||||
}
|
||||
"ln" | "log" | "log10" => {
|
||||
let x = num(one()?)?;
|
||||
if x <= 0.0 {
|
||||
@@ -1214,7 +1254,13 @@ mod tests {
|
||||
// Inside parentheses a comma still separates a function's arguments.
|
||||
assert_eq!(ev("max(1,2)", Kind::Unitless).unwrap(), 2.0);
|
||||
assert_eq!(ev("max(1 mm, 3, 2)", Kind::Length).unwrap(), 3.0);
|
||||
assert_eq!(ev("(2,5)", Kind::Unitless).ok(), None, "a comma inside parentheses is not a decimal comma");
|
||||
// Plain parentheses have no arguments to separate (#9408), also inside a call.
|
||||
assert_eq!(ev("(2,5)", Kind::Unitless).unwrap(), 2.5);
|
||||
assert_eq!(ev("-(width-0,5)/2", Kind::Length).unwrap(), -19.75);
|
||||
assert_eq!(ev("(,5)", Kind::Unitless).unwrap(), 0.5);
|
||||
assert_eq!(ev("(2 1/8,5)", Kind::Unitless).unwrap(), 2.0 / 8.5);
|
||||
assert_eq!(ev("max((1,5), 1)", Kind::Unitless).unwrap(), 1.5);
|
||||
assert_eq!(ev("(max(1,2))", Kind::Unitless).unwrap(), 2.0);
|
||||
// Not between two digits, or a second comma: still an error.
|
||||
for bad in ["2,", "2 ,5", "2, 5", "1,5,3", "1.5,3", ",5,3", ",5.3", "width ,5", "(1) ,5"] {
|
||||
assert!(ev(bad, Kind::Unitless).is_err(), "{bad}");
|
||||
@@ -1328,6 +1374,15 @@ mod tests {
|
||||
assert!((ev("atan2(1; 1)", Kind::Angle).unwrap() - std::f64::consts::FRAC_PI_4).abs() < 1e-12);
|
||||
assert!((ev("exp(ln(5))", Kind::Unitless).unwrap() - 5.0).abs() < 1e-12);
|
||||
assert!((ev("log(1000)", Kind::Unitless).unwrap() - 3.0).abs() < 1e-12);
|
||||
// Hyperbolic functions (#9332): their definitions in exp, identities and inverses.
|
||||
assert!((ev("cosh(1.5) - (exp(1.5) + exp(-1.5)) / 2", Kind::Unitless).unwrap()).abs() < 1e-12);
|
||||
assert!((ev("sinh(1.5) - (exp(1.5) - exp(-1.5)) / 2", Kind::Unitless).unwrap()).abs() < 1e-12);
|
||||
assert!((ev("tanh(0.7) - sinh(0.7) / cosh(0.7)", Kind::Unitless).unwrap()).abs() < 1e-12);
|
||||
assert!((ev("cosh(2) ^ 2 - sinh(2) ^ 2", Kind::Unitless).unwrap() - 1.0).abs() < 1e-12);
|
||||
assert!((ev("asinh(sinh(1.25))", Kind::Unitless).unwrap() - 1.25).abs() < 1e-12);
|
||||
assert!((ev("acosh(cosh(1.25))", Kind::Unitless).unwrap() - 1.25).abs() < 1e-12);
|
||||
assert!((ev("atanh(tanh(0.5))", Kind::Unitless).unwrap() - 0.5).abs() < 1e-12);
|
||||
assert_eq!(ev("cosh(0) + sinh(0) + tanh(0) + asinh(0) + acosh(1) + atanh(0)", Kind::Unitless).unwrap(), 1.0);
|
||||
assert_eq!(ev("floor(2.7) + ceil(0.2) + round(1.5) + abs(-1)", Kind::Unitless).unwrap(), 6.0);
|
||||
assert!((ev("1 rad", Kind::Angle).unwrap() - 1.0).abs() < 1e-12);
|
||||
assert!((ev("acos(0)", Kind::Angle).unwrap() - std::f64::consts::FRAC_PI_2).abs() < 1e-12);
|
||||
@@ -1337,6 +1392,22 @@ mod tests {
|
||||
assert_eq!(ev("width^2 / width", Kind::Length).unwrap(), 40.0);
|
||||
}
|
||||
|
||||
/// The hyperbolic functions (#9332) take a unit-less number, and the inverses refuse what lies
|
||||
/// outside their domain, as `asin` and `ln` do.
|
||||
#[test]
|
||||
fn hyperbolic_functions_refuse_units_and_numbers_outside_their_domain() {
|
||||
for (e, says) in [
|
||||
("cosh(2 mm)", "`cosh` needs a unit-less number"),
|
||||
("tanh(30 deg)", "`tanh` needs a unit-less number"),
|
||||
("acosh(0.5)", "`acosh` needs a number of at least 1"),
|
||||
("atanh(1)", "`atanh` needs a number between -1 and 1"),
|
||||
("atanh(-1.5)", "`atanh` needs a number between -1 and 1"),
|
||||
] {
|
||||
let err = ev(e, Kind::Unitless).map(|v| v.to_string()).unwrap_or_else(|e| e.to_string());
|
||||
assert!(err.contains(says), "{e}: {err}");
|
||||
}
|
||||
}
|
||||
|
||||
/// A count from a length (`(L - 20) / 210`, the 210 read as unit-less) names the fix (#5901).
|
||||
#[test]
|
||||
fn a_length_where_a_count_is_expected_says_to_divide_by_a_length() {
|
||||
@@ -1449,6 +1520,8 @@ mod tests {
|
||||
assert!(is_literal("20") && is_literal("-1.5 in") && is_literal("3 deg"));
|
||||
assert!(!is_literal("d1") && !is_literal("2 * 3") && !is_literal("2 width"));
|
||||
assert!(is_bare_number(" -1.5 ") && is_bare_number("+2") && !is_bare_number("20 mm") && !is_bare_number("(2)"));
|
||||
// A leading `=` only marks a formula (#4681): `=5` is the bare number `5`, not `==5`.
|
||||
assert!(is_bare_number("=5") && is_bare_number(" = -1.5") && !is_bare_number("=5 mm") && !is_bare_number("==5") && !is_bare_number("=d3"));
|
||||
assert_eq!((length_unit_or_mm(" in "), length_unit_or_mm("deg"), length_unit_or_mm("")), ("in", "mm", "mm"));
|
||||
}
|
||||
|
||||
|
||||
@@ -172,32 +172,7 @@ impl Document {
|
||||
author: u64,
|
||||
author_path: &[u64],
|
||||
) -> Result<FaceAnchor> {
|
||||
// A construction certificate that names this face alone, else its exact history name.
|
||||
let certified = body
|
||||
.body
|
||||
.face_plane(index)
|
||||
.ok_or_else(|| DocError::Invalid("this face has no exact planar source; choose a fixed plane instead".into()))
|
||||
.and_then(|source| {
|
||||
let target = self.strong_face_target(body, index, source.origin)?;
|
||||
if target.certificate.is_none() {
|
||||
return Err(DocError::Invalid("this face has no supported construction certificate; choose a fixed plane instead".into()));
|
||||
}
|
||||
let indices = self.configuration_face_indices(body, &target)?;
|
||||
// A copy a pattern or mirror made on the same body carries its seed's certificate,
|
||||
// which finds the seed's face: the copy is attached by its own history name below.
|
||||
if !indices.contains(&index) {
|
||||
return Err(DocError::Invalid("this face has no supported construction certificate; choose a fixed plane instead".into()));
|
||||
}
|
||||
self.coplanar_pieces(body, &indices, |_| true)?;
|
||||
Ok(target)
|
||||
});
|
||||
let target = match certified {
|
||||
Ok(target) => target,
|
||||
Err(error) => match body.body.planar_face(index).and_then(|plane| self.lineage_face_target(body, index, plane.origin)) {
|
||||
Some(target) => target,
|
||||
None => return Err(error),
|
||||
},
|
||||
};
|
||||
let target = self.flat_face_target(body, index)?;
|
||||
let source = self
|
||||
.anchor_face_plane(body, index, target.certificate.as_ref())
|
||||
.ok_or_else(|| DocError::Invalid("this face has no exact planar source; choose a fixed plane instead".into()))?;
|
||||
@@ -220,6 +195,42 @@ impl Document {
|
||||
Ok(anchor)
|
||||
}
|
||||
|
||||
/// A target for flat face `index` of `body` that a rebuild finds again: a construction
|
||||
/// certificate that names this face alone, else its exact history name. What a sketch on a
|
||||
/// face and a print face hold.
|
||||
pub(crate) fn flat_face_target(&self, body: &ModelBody, index: usize) -> Result<ConfigFaceTarget> {
|
||||
let certified = body
|
||||
.body
|
||||
.face_plane(index)
|
||||
.ok_or_else(|| DocError::Invalid("this face has no exact planar source; choose a fixed plane instead".into()))
|
||||
.and_then(|source| {
|
||||
let target = self.strong_face_target(body, index, source.origin)?;
|
||||
if target.certificate.is_none() {
|
||||
return Err(DocError::Invalid("this face has no supported construction certificate; choose a fixed plane instead".into()));
|
||||
}
|
||||
let indices = self.configuration_face_indices(body, &target)?;
|
||||
// A copy a pattern or mirror made on the same body carries its seed's certificate,
|
||||
// which finds the seed's face: the copy is attached by its own history name below.
|
||||
// A face that is no copy, on the plane of the pieces the certificate finds, is
|
||||
// another piece of that face (a piece a later join left bordering another body,
|
||||
// and named after it): the certificate stands for it too (#9465).
|
||||
if !indices.contains(&index) {
|
||||
let names = crate::naming::names(body);
|
||||
let copy = names.faces.get(index).is_none_or(|name| crate::persistent_name::is_copy(name));
|
||||
let all: Vec<usize> = indices.iter().copied().chain([index]).collect();
|
||||
if copy || self.coplanar_pieces(body, &all, |_| true).is_err() {
|
||||
return Err(DocError::Invalid("this face has no supported construction certificate; choose a fixed plane instead".into()));
|
||||
}
|
||||
}
|
||||
self.coplanar_pieces(body, &indices, |_| true)?;
|
||||
Ok(target)
|
||||
});
|
||||
match certified {
|
||||
Ok(target) => Ok(target),
|
||||
Err(error) => body.body.planar_face(index).and_then(|plane| self.lineage_face_target(body, index, plane.origin)).ok_or(error),
|
||||
}
|
||||
}
|
||||
|
||||
/// The faces an attachment stands for, and a note when they were found by fallback.
|
||||
///
|
||||
/// An extrude's cap is certified by the loop of sketch curves around it, so editing that
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
//! Browser groups can nest and be ordered. A group saves its `parent` group (omitted at the top
|
||||
//! level); a group's items and a folder's `browser_order` list may name groups as numbers beside
|
||||
//! item keys as strings; and `browser_order` has a `"<component>/components"` list ordering a
|
||||
//! component's sub-components by placement id. Older designs read unchanged: they have no
|
||||
//! parents and no group entries. The last release refuses the newer format and asks for an
|
||||
//! update instead of dropping the nesting and the order.
|
||||
@@ -0,0 +1,7 @@
|
||||
//! A point cloud keeps the other properties its file gives its points (#8816): named numbers per
|
||||
//! point in `complex` (`columns`, each whole-numbered or not, and the `names` a whole-numbered one's
|
||||
//! values carry), and it can be coloured by one of them (`color_by: "property"`, with
|
||||
//! `color_property`, the ramp over `height_range`) and shown only where `filters` keep it (ranges,
|
||||
//! or sets of named values). Older designs need no transformation: their clouds have no other
|
||||
//! properties and no filters. The last release refuses a design saved with this (the newer format
|
||||
//! number) instead of opening its clouds without their properties, colouring and filters.
|
||||
@@ -0,0 +1,5 @@
|
||||
//! A design saves the print face of its bodies (`print_faces`, by body name): the flat face a
|
||||
//! slicer export lays on the print bed, held by the same face target a sketch on a face holds.
|
||||
//! An older design has none, and every body is exported as it lies, as before. The last
|
||||
//! release refuses a design that has print faces and asks for an update, instead of opening it
|
||||
//! and losing them on the next save.
|
||||
@@ -0,0 +1,5 @@
|
||||
//! A point-to-point Align can save `axes`: the directions it moves along, as the chosen world
|
||||
//! X/Y/Z axes in the frame of the bodies being moved (if it is absent, all three axes are used and
|
||||
//! the offset is applied in full). Older designs need no transformation: they align on all three
|
||||
//! axes as before. The last release refuses a design that has this (it refuses the newer format
|
||||
//! number) rather than moving the bodies on all three axes.
|
||||
@@ -0,0 +1,5 @@
|
||||
//! An equation curve can save `variable_unit: "range"`: its variable is a length, as its range is,
|
||||
//! instead of a plain number (#9333). An older design has none, and its variable stays a plain
|
||||
//! number, as before; a curve with a plain variable saves nothing new. The last release refuses a
|
||||
//! design with this change and asks for an update, instead of opening it and losing the key on the
|
||||
//! next save.
|
||||
@@ -0,0 +1,5 @@
|
||||
//! A linked component's link saves `file_sha256`, the SHA-256 of the linked design file's bytes
|
||||
//! as the assembly last read them, so an assembly opened again knows which linked designs changed
|
||||
//! while it was closed (#9739). Older designs read unchanged: their links have no digest and are
|
||||
//! taken as up to date until Update Links reads them. The last release refuses the newer format
|
||||
//! and asks for an update instead of dropping the digests.
|
||||
@@ -10,6 +10,7 @@ pub mod appearance_pack;
|
||||
mod assembly;
|
||||
mod body_transfer;
|
||||
mod body_transfer_sheet;
|
||||
mod browser_tree;
|
||||
pub mod pbr_appearance;
|
||||
pub use body_transfer::{valid_transfer_matrix, validate_body_transfer};
|
||||
pub mod canvas;
|
||||
@@ -53,6 +54,8 @@ pub mod physical_material;
|
||||
mod piece_names;
|
||||
pub mod pipe_thread_catalog;
|
||||
pub mod point_cloud;
|
||||
mod point_cloud_complex;
|
||||
pub mod point_cloud_distribution;
|
||||
mod points;
|
||||
mod profile_refs;
|
||||
pub mod progress;
|
||||
@@ -61,6 +64,8 @@ pub use thread_catalog::{TappedThread, TappedThreadFamily, parse_tapped_thread,
|
||||
mod walk;
|
||||
pub use profile_refs::{capture_profile_selection, profile_fallback_notes, profile_selection_indices, profile_selection_indices_lenient};
|
||||
pub mod plastic;
|
||||
mod print_face;
|
||||
pub use print_face::PrintFace;
|
||||
pub mod project;
|
||||
mod project3d;
|
||||
pub mod render_aging;
|
||||
|
||||
@@ -571,7 +571,12 @@ pub(crate) fn order_lumps(bodies: &mut [crate::ModelBody], origin: &Arc<crate::n
|
||||
}
|
||||
for (_, members) in families.into_iter().filter(|(_, m)| m.len() > 1) {
|
||||
let feature = members.first().and_then(|i| bodies.get(*i)).map(|b| b.feature);
|
||||
if members.iter().any(|i| bodies.get(*i).map(|b| b.feature) != feature) {
|
||||
// A cut's pieces past the first belong to the cut itself (#10123), so its family spans
|
||||
// two features: the piece that kept the body's name comes from the body's own feature
|
||||
// and the rest from this feature. Any other mix is not a split's family: leave it be.
|
||||
let same = members.iter().all(|i| bodies.get(*i).map(|b| b.feature) == feature);
|
||||
let foreign = members.iter().filter(|i| bodies.get(**i).map(|b| b.feature) != Some(origin.feature.id)).count();
|
||||
if !same && foreign > 1 {
|
||||
continue;
|
||||
}
|
||||
let least = |b: &crate::ModelBody| {
|
||||
|
||||
@@ -22,7 +22,8 @@ pub struct SavedModel {
|
||||
|
||||
/// Records refer to these at most.
|
||||
const MAX_ITEMS: usize = 1_000_000;
|
||||
/// Bodies, sketches and sheet bodies all the states hold together, at most (a state is a list of clones).
|
||||
/// Bodies, sketches, sheet bodies and sketch keys all the states hold together, at most (a state is
|
||||
/// a list of clones).
|
||||
const MAX_HELD: usize = 50_000_000;
|
||||
/// Longest text a record holds (bytes). A feature's warning can quote every generated name of
|
||||
/// the edges it picked: 122,701 characters in one design, whose saved model was refused, so it
|
||||
@@ -48,6 +49,11 @@ fn unhex(v: &Json) -> Result<u64> {
|
||||
v.as_str().and_then(|s| u64::from_str_radix(s, 16).ok()).ok_or_else(|| bad("saved model: key"))
|
||||
}
|
||||
|
||||
/// A sketch-key set's list `key` (`set` or `drop`).
|
||||
fn keys_list<'a>(set: &'a Json, key: &str) -> Result<&'a Vec<Json>> {
|
||||
set.get(key).and_then(Json::as_array).filter(|l| l.len() <= MAX_ITEMS).ok_or_else(|| bad("saved model: sketch keys"))
|
||||
}
|
||||
|
||||
fn bad(what: &str) -> DocError {
|
||||
DocError::Invalid(what.into())
|
||||
}
|
||||
@@ -128,9 +134,36 @@ struct Writer {
|
||||
sheet_index: HashMap<String, usize>,
|
||||
states: Vec<Json>,
|
||||
state_index: HashMap<usize, usize>,
|
||||
/// The states' sketch keys, each distinct map once, written as the changes from the set
|
||||
/// written before it: every state used to repeat the whole map (one entry per solved sketch),
|
||||
/// 85 % of a 5,484-feature design's records, which then did not fit the cache's manifest.
|
||||
sketch_key_sets: Vec<Json>,
|
||||
sketch_key_index: HashMap<BTreeMap<u64, u64>, usize>,
|
||||
last_sketch_keys: Option<(BTreeMap<u64, u64>, usize)>,
|
||||
}
|
||||
|
||||
impl Writer {
|
||||
/// The place of `keys` among the sketch-key sets, written the first time a state holds them
|
||||
/// (as the changes from the set written last: a later state mostly adds a sketch or two).
|
||||
fn sketch_key_set(&mut self, keys: &BTreeMap<u64, u64>) -> usize {
|
||||
if let Some(i) = self.sketch_key_index.get(keys) {
|
||||
return *i;
|
||||
}
|
||||
let record = match &self.last_sketch_keys {
|
||||
Some((base, at)) => {
|
||||
let set: Vec<Json> = keys.iter().filter(|(f, k)| base.get(f) != Some(k)).map(|(f, k)| json!([f, hex(*k)])).collect();
|
||||
let drop: Vec<u64> = base.keys().filter(|f| !keys.contains_key(f)).copied().collect();
|
||||
json!({"base": at, "set": set, "drop": drop})
|
||||
}
|
||||
None => json!({"set": keys.iter().map(|(f, k)| json!([f, hex(*k)])).collect::<Vec<_>>(), "drop": []}),
|
||||
};
|
||||
self.sketch_key_sets.push(record);
|
||||
let i = self.sketch_key_sets.len() - 1;
|
||||
self.sketch_key_index.insert(keys.clone(), i);
|
||||
self.last_sketch_keys = Some((keys.clone(), i));
|
||||
i
|
||||
}
|
||||
|
||||
fn names(&mut self, b: &ModelBody) -> usize {
|
||||
let id = b.names.id();
|
||||
if let Some(i) = self.names_index.get(&id) {
|
||||
@@ -144,9 +177,6 @@ impl Writer {
|
||||
}
|
||||
|
||||
fn model_body(&mut self, b: &ModelBody) -> Option<usize> {
|
||||
if b.body.is_mesh() {
|
||||
return None;
|
||||
}
|
||||
let key = BodyKey::of(b);
|
||||
if let Some(i) = self.model_body_index.get(&key) {
|
||||
return Some(*i);
|
||||
@@ -216,7 +246,7 @@ impl Writer {
|
||||
"reserved_body_names": st.reserved_body_names.iter().collect::<Vec<_>>(),
|
||||
"sheets": sheets, "construct": serde_json::to_value(&st.construct).ok()?,
|
||||
"threads": serde_json::to_value(&st.threads).ok()?,
|
||||
"sketch_keys": st.sketch_keys.iter().map(|(f, k)| json!([f, hex(*k)])).collect::<Vec<_>>(),
|
||||
"sketch_key_set": self.sketch_key_set(&st.sketch_keys),
|
||||
"blend_edges": serde_json::to_value(&st.blend_edges).ok()?, "fitted": serde_json::to_value(&st.fitted).ok()?,
|
||||
"tapered": serde_json::to_value(&st.tapered).ok()?,
|
||||
});
|
||||
@@ -228,7 +258,7 @@ impl Writer {
|
||||
|
||||
impl Model {
|
||||
/// The model as a design file keeps it: `None` unless it is `doc`'s evaluation without an
|
||||
/// error, holds no mesh bodies, and `doc` keeps no names saved before format 14. Works out
|
||||
/// error and `doc` keeps no names saved before format 14. Works out
|
||||
/// the face names not asked for yet (a saved model keeps them as worked out).
|
||||
pub fn saved(&self, doc: &Document) -> Option<SavedModel> {
|
||||
if self.results.is_empty() || self.results.iter().any(|r| r.error.is_some()) || !self.is_current(doc) || has_legacy_names(doc) {
|
||||
@@ -250,7 +280,7 @@ impl Model {
|
||||
}
|
||||
let records = json!({
|
||||
"features": features, "states": w.states, "model_bodies": w.model_bodies, "names": w.names, "sketches": w.sketches,
|
||||
"sheets": w.sheets,
|
||||
"sheets": w.sheets, "sketch_key_sets": w.sketch_key_sets,
|
||||
});
|
||||
Ok(SavedModel { records, bodies: w.bodies })
|
||||
})
|
||||
@@ -331,9 +361,49 @@ impl SavedModel {
|
||||
for s in list("sheets")? {
|
||||
sheets.push(serde_json::from_value::<crate::sheet::SheetBody>(s.clone()).map_err(|_| bad("saved model: sheet"))?);
|
||||
}
|
||||
let mut states = Vec::new();
|
||||
// The sketch-key sets, each the changes from an earlier one (`base`): a short record can
|
||||
// stand for a large set, so what they hold counts towards MAX_HELD as they are built.
|
||||
let mut key_sets: Vec<BTreeMap<u64, u64>> = Vec::new();
|
||||
let mut held = 0usize;
|
||||
for s in list("states")? {
|
||||
for k in list("sketch_key_sets")? {
|
||||
// A set is the changes from one before it.
|
||||
let base = match k.get("base") {
|
||||
Some(b) => Some(key_sets.get(index(Some(b), key_sets.len())?).ok_or_else(|| bad("saved model: sketch keys"))?),
|
||||
None => None,
|
||||
};
|
||||
let (drop, set) = (keys_list(k, "drop")?, keys_list(k, "set")?);
|
||||
// Counted before the base is copied: at most what the set can hold.
|
||||
held = held.saturating_add(base.map_or(0, BTreeMap::len)).saturating_add(set.len());
|
||||
if held > MAX_HELD {
|
||||
return Err(bad("saved model: sketch keys"));
|
||||
}
|
||||
let mut keys = base.cloned().unwrap_or_default();
|
||||
for f in drop {
|
||||
keys.remove(&f.as_u64().ok_or_else(|| bad("saved model: sketch keys"))?);
|
||||
}
|
||||
for e in set {
|
||||
keys.insert(e.get(0).and_then(Json::as_u64).ok_or_else(|| bad("saved model: sketch keys"))?, unhex(e.get(1).unwrap_or(&Json::Null))?);
|
||||
}
|
||||
key_sets.push(keys);
|
||||
}
|
||||
let records = list("states")?;
|
||||
// What every state holds, counted from its runs and its sketch-key set before any is
|
||||
// built (a hostile file cannot make the states clone more than MAX_HELD items).
|
||||
for s in records {
|
||||
for key in ["bodies", "sketches"] {
|
||||
for run in s.get(key).and_then(Json::as_array).ok_or_else(|| bad("saved model: state"))? {
|
||||
held = held.saturating_add(run.get(1).and_then(Json::as_u64).and_then(|n| usize::try_from(n).ok()).unwrap_or(usize::MAX));
|
||||
}
|
||||
}
|
||||
held = held.saturating_add(s.get("sheets").and_then(Json::as_array).map_or(0, Vec::len));
|
||||
held = held.saturating_add(key_sets.get(index(s.get("sketch_key_set"), key_sets.len())?).map_or(0, BTreeMap::len));
|
||||
if held > MAX_HELD {
|
||||
return Err(bad("saved model: states"));
|
||||
}
|
||||
}
|
||||
// Each state is independent of the others once the records they share are read: built
|
||||
// on threads (a 5,484-feature design spent 3.5 s building them one after another).
|
||||
let built = kernel::map_on_threads(records, 16, |s: &Json| -> Result<ModelState> {
|
||||
// Runs of consecutive indices, each within the list it indexes.
|
||||
let ids = |key: &str, len: usize| -> Result<Vec<usize>> {
|
||||
let mut out = Vec::new();
|
||||
@@ -349,12 +419,8 @@ impl SavedModel {
|
||||
};
|
||||
let field = |key: &str| parse(s.get(key));
|
||||
let invalid = |_| bad("saved model: state");
|
||||
let mut sketch_keys = BTreeMap::new();
|
||||
for k in s.get("sketch_keys").and_then(Json::as_array).ok_or_else(|| bad("saved model: state"))? {
|
||||
sketch_keys
|
||||
.insert(k.get(0).and_then(Json::as_u64).ok_or_else(|| bad("saved model: state"))?, unhex(k.get(1).unwrap_or(&Json::Null))?);
|
||||
}
|
||||
let st = ModelState {
|
||||
let sketch_keys = key_sets.get(index(s.get("sketch_key_set"), key_sets.len())?).cloned().ok_or_else(|| bad("saved model: state"))?;
|
||||
Ok(ModelState {
|
||||
frame_bodies: Default::default(),
|
||||
bodies: ids("bodies", model_bodies.len())?.into_iter().filter_map(|i| model_bodies.get(i).cloned()).collect(),
|
||||
sketches: ids("sketches", sketches.len())?.into_iter().filter_map(|i| sketches.get(i).cloned()).collect(),
|
||||
@@ -377,13 +443,9 @@ impl SavedModel {
|
||||
blend_edges: serde_json::from_value(field("blend_edges")?).map_err(invalid)?,
|
||||
fitted: serde_json::from_value(field("fitted")?).map_err(invalid)?,
|
||||
tapered: serde_json::from_value(field("tapered")?).map_err(invalid)?,
|
||||
};
|
||||
held = held.saturating_add(st.bodies.len()).saturating_add(st.sketches.len()).saturating_add(st.sheets.len());
|
||||
if held > MAX_HELD {
|
||||
return Err(bad("saved model: states"));
|
||||
}
|
||||
states.push(Arc::new(st));
|
||||
}
|
||||
})
|
||||
});
|
||||
let states = built.into_iter().map(|r| r.unwrap_or_else(|| Err(bad("saved model: state"))).map(Arc::new)).collect::<Result<Vec<_>>>()?;
|
||||
Ok(states)
|
||||
}
|
||||
|
||||
@@ -457,7 +519,8 @@ impl SavedModel {
|
||||
let mut stored = std::collections::HashSet::new();
|
||||
// The sheet bodies, each written once and named by place in the states: all kept.
|
||||
let sheets = list("sheets").cloned().unwrap_or_default();
|
||||
let mut used = bytes(sheets.as_slice()).iter().fold(0usize, |t, b| t.saturating_add(*b));
|
||||
let key_sets = list("sketch_key_sets").cloned().unwrap_or_default();
|
||||
let mut used = bytes(sheets.as_slice()).iter().chain(bytes(key_sets.as_slice()).iter()).fold(0usize, |t, b| t.saturating_add(*b));
|
||||
for s in std::iter::once(last).chain(order) {
|
||||
let (mut adds, mut new_names, mut new_sketches) = (HashMap::new(), std::collections::HashSet::new(), std::collections::HashSet::new());
|
||||
let mut records = *state_bytes.get(s)?;
|
||||
@@ -549,7 +612,7 @@ impl SavedModel {
|
||||
}
|
||||
let records = json!({
|
||||
"features": out_features, "states": out_states, "model_bodies": out_bodies, "names": kept_of(names.as_slice(), &names_used),
|
||||
"sketches": kept_of(sketches.as_slice(), &sketches_used), "sheets": sheets,
|
||||
"sketches": kept_of(sketches.as_slice(), &sketches_used), "sheets": sheets, "sketch_key_sets": key_sets,
|
||||
});
|
||||
let kept: Vec<usize> = (0..self.bodies.len()).filter(|i| kernel_used.get(*i) == Some(&true)).collect();
|
||||
let bodies = kept.iter().filter_map(|i| self.bodies.get(*i).cloned()).collect();
|
||||
|
||||
@@ -462,7 +462,7 @@ impl Document {
|
||||
|
||||
/// User parameters as CSV (`name,unit,expression,value,comment`).
|
||||
pub fn params_csv(&self) -> String {
|
||||
let q = |s: &str| if s.contains([',', '"', '\n']) { format!("\"{}\"", s.replace('"', "\"\"")) } else { s.to_string() };
|
||||
let q = |s: &str| if s.contains([',', '"', '\r', '\n']) { format!("\"{}\"", s.replace('"', "\"\"")) } else { s.to_string() };
|
||||
let mut out = String::from("name,unit,expression,value,comment,favorite\n");
|
||||
for r in self.param_rows().into_iter().filter(|r| r.source == "user") {
|
||||
out += &format!(
|
||||
@@ -497,23 +497,25 @@ impl Document {
|
||||
})
|
||||
.collect::<Result<_>>()?
|
||||
} else {
|
||||
let mut lines = text.lines();
|
||||
let header: Vec<String> = parse_csv_line(lines.next().unwrap_or_default()).into_iter().map(|h| h.trim().to_ascii_lowercase()).collect();
|
||||
let col = |n: &str| header.iter().position(|h| h == n);
|
||||
let mut records = split_csv(text.strip_prefix('\u{feff}').unwrap_or(text), '\n');
|
||||
let header = csv_fields(records.next().unwrap_or_default())?;
|
||||
let col = |n: &str| header.iter().position(|h| h.trim().eq_ignore_ascii_case(n));
|
||||
let (Some(ni), Some(ei)) = (col("name"), col("expression").or(col("value"))) else {
|
||||
return Err(DocError::Invalid("the CSV needs `name` and `expression` columns".into()));
|
||||
};
|
||||
let (ui, ci) = (col("unit"), col("comment"));
|
||||
lines
|
||||
.filter(|l| !l.trim().is_empty())
|
||||
.map(|l| {
|
||||
let c = parse_csv_line(l);
|
||||
records
|
||||
.filter(|record| !record.trim().is_empty())
|
||||
.take(MAX_PARAMS + 1)
|
||||
.map(|record| {
|
||||
let c = csv_fields(record)?;
|
||||
let get = |i: Option<usize>| i.and_then(|i| c.get(i)).map(|s| s.trim().to_string());
|
||||
(get(Some(ni)).unwrap_or_default(), get(Some(ei)).unwrap_or_default(), get(ui), get(ci))
|
||||
let comment = ci.and_then(|i| c.get(i)).cloned();
|
||||
Ok((get(Some(ni)).unwrap_or_default(), get(Some(ei)).unwrap_or_default(), get(ui), comment))
|
||||
})
|
||||
.collect()
|
||||
.collect::<Result<_>>()?
|
||||
};
|
||||
if rows.len() > 10_000 {
|
||||
if rows.len() > MAX_PARAMS {
|
||||
return Err(DocError::Invalid("too many parameters".into()));
|
||||
}
|
||||
// Each row is checked and applied as `change_param` would, but the parameters are
|
||||
@@ -1069,25 +1071,32 @@ impl Document {
|
||||
}
|
||||
}
|
||||
|
||||
/// One CSV line with quoted fields.
|
||||
fn parse_csv_line(l: &str) -> Vec<String> {
|
||||
let mut out = Vec::new();
|
||||
let mut cur = String::new();
|
||||
/// Split records or fields only outside quotes. A doubled quote toggles twice
|
||||
/// before the next separator, leaving it inside the same field.
|
||||
fn split_csv(text: &str, separator: char) -> impl Iterator<Item = &str> {
|
||||
let mut quoted = false;
|
||||
let mut chars = l.chars().peekable();
|
||||
while let Some(c) = chars.next() {
|
||||
match (c, quoted) {
|
||||
('"', true) if chars.peek() == Some(&'"') => {
|
||||
cur.push('"');
|
||||
chars.next();
|
||||
}
|
||||
('"', _) => quoted = !quoted,
|
||||
(',', false) => out.push(std::mem::take(&mut cur)),
|
||||
(c, _) => cur.push(c),
|
||||
text.split(move |c| {
|
||||
if c == '"' {
|
||||
quoted = !quoted;
|
||||
}
|
||||
}
|
||||
out.push(cur);
|
||||
out
|
||||
c == separator && !quoted
|
||||
})
|
||||
}
|
||||
|
||||
fn csv_fields(record: &str) -> Result<Vec<String>> {
|
||||
split_csv(record, ',')
|
||||
.map(|raw| {
|
||||
let field = raw.trim();
|
||||
if !field.contains('"') {
|
||||
return Ok(field.to_string());
|
||||
}
|
||||
let inner = field.strip_prefix('"').and_then(|s| s.strip_suffix('"'));
|
||||
match inner {
|
||||
Some(s) if s.split("\"\"").all(|part| !part.contains('"')) => Ok(s.replace("\"\"", "\"")),
|
||||
_ => Err(DocError::Invalid("invalid quoting in parameter CSV".into())),
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Parameters whose definitions depend on each other in a loop.
|
||||
@@ -1150,6 +1159,19 @@ mod design_length_tests {
|
||||
assert_eq!(written("", 5.0), w("mm", "5 mm"));
|
||||
}
|
||||
|
||||
/// A bare number typed as a formula (`=5`) means the design's units like `5` does.
|
||||
#[test]
|
||||
fn a_formula_that_is_a_bare_number_gets_the_design_unit() {
|
||||
let mut doc = Document::new("Units");
|
||||
doc.units = "in".into();
|
||||
let length = crate::expr::Kind::Length;
|
||||
assert_eq!(doc.with_design_unit("5", length), "5 in");
|
||||
assert_eq!(doc.with_design_unit("=5", length), "=5 in");
|
||||
assert_eq!(doc.with_design_unit("=5 mm", length), "=5 mm");
|
||||
let inches = doc.eval(&doc.with_design_unit("=5", length), length).unwrap();
|
||||
assert!((inches - 127.0).abs() < 1e-9, "{inches}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_written_value_reads_back_within_a_micrometre() {
|
||||
for units in ["mm", "cm", "m", "in", "ft"] {
|
||||
|
||||
@@ -152,6 +152,27 @@ pub enum NameError {
|
||||
},
|
||||
}
|
||||
|
||||
/// Whether `text` can be written into a name whole.
|
||||
///
|
||||
/// A curve's id goes into the name of the faces the curve makes (`F2:side:<id>`), and a
|
||||
/// name reads some characters as its own: `|` separates the faces of an edge, `,` the faces
|
||||
/// around a piece, `~` numbers the edges between two faces, `#` numbers a piece and `]`
|
||||
/// closes one. An id holding one of them splits every name it lands in: the id `c|1` gave
|
||||
/// the edges of an extrusion the names `F2:side:c|1#1|F2:side:c|1#2~1`, three separators
|
||||
/// where an edge names two faces and separates them once (#5858).
|
||||
///
|
||||
/// The test is the name's own round trip rather than a list of characters: the text is
|
||||
/// written into a name and read back, and it must read back as itself. A list would have
|
||||
/// to follow every change of the grammar (#5861), and would miss an id that reads back as
|
||||
/// something else (`s1.l4` reads as profile 1 of curve `l4`).
|
||||
pub fn text_fits_name(text: &str) -> bool {
|
||||
let name = format!("F0:side:{text}");
|
||||
match FaceName::parse(&name) {
|
||||
Ok(f) => f.to_string() == name && matches!(&f.base, Base::Made { role: Role::Side { profile: None, curve }, .. } if curve == text),
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl FaceName {
|
||||
/// The feature that made the face: its base's, a copy's when it is one.
|
||||
pub fn feature(&self) -> Option<FeatureId> {
|
||||
|
||||
@@ -236,3 +236,15 @@ fn hostile_names_never_panic() {
|
||||
// A fillet on an open boundary's edge.
|
||||
assert!(matches!(face("F1:blend:F10:start").base, Base::Blend { rounds: Rounds::Edge(ref e), .. } if e.faces.len() == 1));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_text_that_cannot_be_written_into_a_name_whole_is_told() {
|
||||
// A curve's id goes into the name of the faces the curve makes, so it has to come
|
||||
// back out of the name as itself (#5858).
|
||||
for good in ["c1", "l4", "s01.l4", "c-1", "c_1", "a.b", "x"] {
|
||||
assert!(text_fits_name(good), "`{good}` fits a name");
|
||||
}
|
||||
for bad in ["c|1", "c,1", "c~1", "c]1", "c#1", "", "s1.l4"] {
|
||||
assert!(!text_fits_name(bad), "`{bad}` does not fit a name");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ impl Model {
|
||||
return false;
|
||||
}
|
||||
self.evaluate(doc);
|
||||
self.mark_fingerprinted(doc);
|
||||
if !self.no_cache && self.primed.is_none() && self.placement_local {
|
||||
self.placement_inputs = Some(Inputs { document: doc.clone(), state: Arc::downgrade(&self.state()) });
|
||||
}
|
||||
@@ -38,13 +39,16 @@ impl Model {
|
||||
}
|
||||
|
||||
/// [`Model::refingerprint`] for a shared document: a proof that held for the results before
|
||||
/// is kept for `doc`, since nothing was built differently (pinned body names, say).
|
||||
pub fn refingerprint_shared(&mut self, doc: &Arc<Document>) {
|
||||
/// is kept for `doc`, since nothing was built differently (pinned body names, say). The
|
||||
/// first `keep` results keep their fingerprints: [`Model::pinned_prefix`] of the document
|
||||
/// before the pins, or 0.
|
||||
pub fn refingerprint_shared(&mut self, doc: &Arc<Document>, keep: usize) {
|
||||
let proven = !self.no_cache
|
||||
&& self.primed.is_none()
|
||||
&& self.placement_inputs.as_ref().is_some_and(|inputs| inputs.state.upgrade().is_some_and(|state| Arc::ptr_eq(&state, &self.state())))
|
||||
&& !self.is_stale();
|
||||
self.refingerprint(doc);
|
||||
self.refingerprint_from(doc, keep);
|
||||
self.mark_fingerprinted(doc);
|
||||
if proven && self.placement_local {
|
||||
self.placement_inputs = Some(Inputs { document: doc.clone(), state: Arc::downgrade(&self.state()) });
|
||||
}
|
||||
@@ -127,6 +131,7 @@ fn same_geometry_inputs(a: &Document, b: &Document) -> bool {
|
||||
text_params,
|
||||
next_component_color_index,
|
||||
materials,
|
||||
print_faces,
|
||||
user_materials,
|
||||
appearances,
|
||||
body_components,
|
||||
@@ -162,6 +167,7 @@ fn same_geometry_inputs(a: &Document, b: &Document) -> bool {
|
||||
&& *text_params == b.text_params
|
||||
&& *next_component_color_index == b.next_component_color_index
|
||||
&& *materials == b.materials
|
||||
&& *print_faces == b.print_faces
|
||||
&& *user_materials == b.user_materials
|
||||
&& *appearances == b.appearances
|
||||
&& *body_components == b.body_components
|
||||
|
||||
@@ -11,6 +11,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use solidcraft_geom::Vec3;
|
||||
|
||||
use crate::canvas::{base64_decode, base64_encode};
|
||||
pub use crate::point_cloud_complex::{Column, Complex, Filter, Floats, Keep, MAX_COLUMNS, MAX_NAMES, Names};
|
||||
use crate::{DocError, IDENTITY, Mat, Result};
|
||||
|
||||
/// Most points one cloud may hold.
|
||||
@@ -19,6 +20,10 @@ pub const MAX_POINTS: usize = 20_000_000;
|
||||
pub const MAX_COORD: f64 = 1e9;
|
||||
/// Point sizes on screen (pixels).
|
||||
pub const POINT_SIZE: std::ops::RangeInclusive<f64> = 0.5..=16.0;
|
||||
/// Most filters on one cloud.
|
||||
pub const MAX_FILTERS: usize = 8;
|
||||
/// Properties every cloud has besides its file's: the coordinates in the design.
|
||||
pub const COORDINATES: [&str; 3] = ["x", "y", "z"];
|
||||
/// Length units a point cloud file may be in, and millimetres per unit.
|
||||
pub const UNITS: [(&str, f64); 5] = [("mm", 1.0), ("cm", 10.0), ("m", 1000.0), ("in", 25.4), ("ft", 304.8)];
|
||||
|
||||
@@ -65,6 +70,24 @@ pub struct PointCloud {
|
||||
pub height_range: Option<[f64; 2]>,
|
||||
#[serde(default = "yes")]
|
||||
pub visible: bool,
|
||||
/// The file's other properties of the points.
|
||||
#[serde(default, skip_serializing_if = "Complex::is_empty")]
|
||||
pub complex: Complex,
|
||||
/// The property `color_by: property` colours by.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub color_property: Option<String>,
|
||||
/// Only the points every filter keeps are shown.
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub filters: Vec<Filter>,
|
||||
}
|
||||
|
||||
/// Where a property's values come from.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Source<'a> {
|
||||
/// A coordinate of each point in the design.
|
||||
Coordinate(usize),
|
||||
/// A column of the file: each point's.
|
||||
Column(&'a [f32]),
|
||||
}
|
||||
|
||||
/// How a cloud's points are coloured.
|
||||
@@ -78,6 +101,8 @@ pub enum ColorBy {
|
||||
Single,
|
||||
/// By height in the design: blue low, through cyan, green and yellow, to red high.
|
||||
Height,
|
||||
/// By `color_property`: the height ramp over its range or, for whole numbers, a palette.
|
||||
Property,
|
||||
}
|
||||
|
||||
impl ColorBy {
|
||||
@@ -90,6 +115,7 @@ impl ColorBy {
|
||||
"file" => Some(ColorBy::File),
|
||||
"single" => Some(ColorBy::Single),
|
||||
"height" => Some(ColorBy::Height),
|
||||
"property" => Some(ColorBy::Property),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -98,6 +124,7 @@ impl ColorBy {
|
||||
ColorBy::File => "file",
|
||||
ColorBy::Single => "single",
|
||||
ColorBy::Height => "height",
|
||||
ColorBy::Property => "property",
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,6 +147,27 @@ pub fn height_ramp(t: f64) -> [u8; 3] {
|
||||
std::array::from_fn(|c| (a[c] * (1.0 - f) + b[c] * f).round().clamp(0.0, 255.0) as u8)
|
||||
}
|
||||
|
||||
/// Colours of whole-number labels, the label modulo their count; negative labels are grey.
|
||||
pub const PALETTE: [[u8; 3]; 10] = [
|
||||
[240, 140, 40],
|
||||
[245, 205, 65],
|
||||
[230, 65, 65],
|
||||
[165, 75, 190],
|
||||
[65, 190, 115],
|
||||
[75, 150, 220],
|
||||
[240, 120, 180],
|
||||
[140, 105, 75],
|
||||
[120, 215, 215],
|
||||
[190, 190, 80],
|
||||
];
|
||||
|
||||
pub fn label_color(v: f64) -> [u8; 3] {
|
||||
if !(v.is_finite() && v >= 0.0) {
|
||||
return PLAIN.map(byte);
|
||||
}
|
||||
PALETTE[(v.round() as usize) % PALETTE.len()]
|
||||
}
|
||||
|
||||
/// A colour channel (0..1) as a byte.
|
||||
pub fn byte(v: f32) -> u8 {
|
||||
(v.clamp(0.0, 1.0) * 255.0).round() as u8
|
||||
@@ -182,15 +230,57 @@ impl PointCloud {
|
||||
let (lo, hi) = (at(HEIGHT_TAIL)?, at(1.0 - HEIGHT_TAIL)?);
|
||||
Some(if hi - lo > 1e-9 { [lo, hi] } else { [lo - 0.5, lo + 0.5] })
|
||||
}
|
||||
/// The property colours come from: a column, or a coordinate (`z` for the height ramp).
|
||||
pub fn colored_property(&self) -> Option<&str> {
|
||||
match self.color_by {
|
||||
ColorBy::Height => Some("z"),
|
||||
ColorBy::Property => self.color_property.as_deref(),
|
||||
ColorBy::File | ColorBy::Single => None,
|
||||
}
|
||||
}
|
||||
/// Where the values of `name` are: a coordinate of each point or a column of the file.
|
||||
pub fn source(&self, name: &str) -> Option<Source<'_>> {
|
||||
if let Some(k) = COORDINATES.iter().position(|n| *n == name) {
|
||||
return Some(Source::Coordinate(k));
|
||||
}
|
||||
self.complex.column(name).map(|col| Source::Column(&col.values.0))
|
||||
}
|
||||
/// Every property the cloud can be coloured and filtered by: its coordinates, then its columns.
|
||||
pub fn property_names(&self) -> impl Iterator<Item = &str> {
|
||||
COORDINATES.into_iter().chain(self.complex.columns.iter().map(|c| c.name.as_str()))
|
||||
}
|
||||
/// The smallest and largest value of a property, the coordinates in the design.
|
||||
pub fn span(&self, property: &str) -> Option<[f64; 2]> {
|
||||
if let Some(span) = self.complex.span(property) {
|
||||
return Some(span);
|
||||
}
|
||||
let k = COORDINATES.iter().position(|n| *n == property)?;
|
||||
let v = self.world_corners()?.map(|p| [p.x, p.y, p.z][k]);
|
||||
Some([v.iter().copied().fold(f64::INFINITY, f64::min), v.iter().copied().fold(f64::NEG_INFINITY, f64::max)])
|
||||
}
|
||||
/// The ramp's range as far as it can be told without the elements: the one set, or else the
|
||||
/// coloured property's span within every range filtering it. The automatic range colouring
|
||||
/// by a property is exactly what the filters keep
|
||||
/// ([`crate::point_cloud_distribution::color_range`]), which this bounds.
|
||||
pub fn color_range(&self) -> Option<[f64; 2]> {
|
||||
if self.height_range.is_some() {
|
||||
return self.height_range;
|
||||
}
|
||||
let property = self.colored_property()?;
|
||||
let span = if self.color_by == ColorBy::Height { self.auto_height_range() } else { self.span(property) }?;
|
||||
let shown =
|
||||
self.filters.iter().filter(|f| f.property == property).filter_map(Filter::range).fold(span, |[lo, hi], [a, b]| [lo.max(a), hi.min(b)]);
|
||||
Some(if shown[0] <= shown[1] { crate::point_cloud_distribution::ramp_range(shown) } else { span })
|
||||
}
|
||||
/// The heights the height ramp runs between now: the cloud's own, else the automatic ones.
|
||||
pub fn height_range_now(&self) -> Option<[f64; 2]> {
|
||||
self.height_range.or_else(|| self.auto_height_range())
|
||||
}
|
||||
/// The colour of each point (by index) as the cloud is shown.
|
||||
pub fn shade(&self) -> impl Fn(usize) -> [u8; 3] + '_ {
|
||||
/// The colour of each point (by index) as the cloud is shown, the ramp over `range`.
|
||||
pub fn shade(&self, range: Option<[f64; 2]>) -> impl Fn(usize) -> [u8; 3] + '_ {
|
||||
let single = self.color.unwrap_or(PLAIN).map(byte);
|
||||
let plain = PLAIN.map(byte);
|
||||
let range = if self.color_by == ColorBy::Height { self.height_range_now() } else { None };
|
||||
let column = self.color_property.as_deref().and_then(|n| self.complex.column(n));
|
||||
move |i| match self.color_by {
|
||||
ColorBy::File => self.colors.get(i).unwrap_or(plain),
|
||||
ColorBy::Single => single,
|
||||
@@ -198,6 +288,14 @@ impl PointCloud {
|
||||
(Some([lo, hi]), Some(p)) => height_ramp((self.world_z(p) - lo) / (hi - lo)),
|
||||
_ => plain,
|
||||
},
|
||||
ColorBy::Property => match (column, column.and_then(|c| c.values.0.get(i))) {
|
||||
(Some(c), Some(v)) if c.integer => label_color(f64::from(*v)),
|
||||
(Some(_), Some(v)) => match range {
|
||||
Some([lo, hi]) if hi > lo => height_ramp((f64::from(*v) - lo) / (hi - lo)),
|
||||
_ => plain,
|
||||
},
|
||||
_ => plain,
|
||||
},
|
||||
}
|
||||
}
|
||||
/// The corners of the box around the points, placed in the design (mm).
|
||||
@@ -240,6 +338,18 @@ impl PointCloud {
|
||||
if !rigid(&self.transform) {
|
||||
return bad("its placement is not a rigid move");
|
||||
}
|
||||
self.complex.check(self.points.len())?;
|
||||
if self.filters.len() > MAX_FILTERS
|
||||
|| self.filters.iter().any(|f| match &f.keep {
|
||||
Keep::Range { range: [lo, hi] } => !(lo.is_finite() && hi.is_finite() && lo <= hi),
|
||||
Keep::Values { values } => values.len() > MAX_NAMES,
|
||||
})
|
||||
{
|
||||
return bad("its filters are not ranges, lowest first");
|
||||
}
|
||||
if self.color_by == ColorBy::Property && self.color_property.is_none() {
|
||||
return bad("it is coloured by a property without naming it");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -422,6 +532,9 @@ mod tests {
|
||||
color: None,
|
||||
height_range: None,
|
||||
visible: true,
|
||||
complex: Complex::default(),
|
||||
color_property: None,
|
||||
filters: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -443,6 +556,20 @@ mod tests {
|
||||
assert_eq!((unit_scale("M"), unit_scale("yd")), (Some(1000.0), None));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_ramp_spans_what_is_shown_unless_set() {
|
||||
let mut c = cloud(vec![0.0; 9], Vec::new());
|
||||
c.complex.columns.push(Column { name: "t".into(), integer: false, values: Floats(vec![0.0, 10.0, 20.0].into()) });
|
||||
(c.color_by, c.color_property) = (ColorBy::Property, Some("t".into()));
|
||||
assert_eq!(c.color_range(), Some([0.0, 20.0]), "the whole span");
|
||||
c.filters = vec![Filter { property: "t".into(), keep: Keep::Range { range: [5.0, 50.0] } }];
|
||||
assert_eq!(c.color_range(), Some([5.0, 20.0]), "the span within the filter");
|
||||
c.filters.push(Filter { property: "layer".into(), keep: Keep::Range { range: [0.0, 1.0] } });
|
||||
assert_eq!(c.color_range(), Some([5.0, 20.0]), "another property's filter changes nothing");
|
||||
c.height_range = Some([1.0, 2.0]);
|
||||
assert_eq!(c.color_range(), Some([1.0, 2.0]), "a range set is kept");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn damaged_clouds_are_refused() {
|
||||
// Not whole points, not finite, not base64.
|
||||
@@ -474,26 +601,26 @@ mod tests {
|
||||
let colors: Vec<u8> = (0..102).flat_map(|i| [i as u8, 7, 9]).collect();
|
||||
let mut c = cloud(values, colors);
|
||||
c.origin = Vec3::ZERO;
|
||||
assert_eq!(c.shade()(3), [3, 7, 9], "the file's colours");
|
||||
assert_eq!(c.shade(c.color_range())(3), [3, 7, 9], "the file's colours");
|
||||
c.colors = Colors::default();
|
||||
assert_eq!(c.shade()(3), PLAIN.map(byte), "none: plain");
|
||||
assert_eq!(c.shade(c.color_range())(3), PLAIN.map(byte), "none: plain");
|
||||
c.color_by = ColorBy::Single;
|
||||
c.color = Some([1.0, 0.5, 0.0]);
|
||||
assert_eq!(c.shade()(50), [255, 128, 0]);
|
||||
assert_eq!(c.shade(c.color_range())(50), [255, 128, 0]);
|
||||
// The stray point doesn't stretch the automatic range.
|
||||
c.color_by = ColorBy::Height;
|
||||
// 102 points: the 2nd and the 99th (of 0…101) once sorted.
|
||||
assert_eq!(c.auto_height_range(), Some([2.0, 99.0]));
|
||||
{
|
||||
let shade = c.shade();
|
||||
let shade = c.shade(c.color_range());
|
||||
assert_eq!((shade(0), shade(100), shade(101)), (height_ramp(0.0), height_ramp(1.0), height_ramp(1.0)));
|
||||
assert_eq!(shade(50), height_ramp(48.0 / 97.0));
|
||||
}
|
||||
// A range of its own; moved up 100 mm, everything is above it.
|
||||
c.height_range = Some([0.0, 50.0]);
|
||||
assert_eq!(c.shade()(25), height_ramp(0.5));
|
||||
assert_eq!(c.shade(c.color_range())(25), height_ramp(0.5));
|
||||
c.transform[3][2] = 100.0;
|
||||
assert_eq!(c.shade()(0), height_ramp(1.0));
|
||||
assert_eq!(c.shade(c.color_range())(0), height_ramp(1.0));
|
||||
assert_eq!((height_ramp(0.0), height_ramp(1.0), height_ramp(f64::NAN)), ([40, 70, 200], [230, 70, 50], [40, 70, 200]));
|
||||
let back: PointCloud = serde_json::from_str(&serde_json::to_string(&c).unwrap()).unwrap();
|
||||
assert_eq!(back, c);
|
||||
|
||||
@@ -0,0 +1,215 @@
|
||||
//! What a point cloud holds besides its points' places and colours: named numbers on its points
|
||||
//! (a PLY file's other vertex properties), to colour the cloud by and to filter it with. Whole
|
||||
//! numbers may have names (`role: 0 outer wall, 1 inner wall` in a PLY file's comments): they
|
||||
//! are labels, filtered by a set of values rather than a range.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::canvas::{base64_decode, base64_encode};
|
||||
use crate::point_cloud::MAX_POINTS;
|
||||
use crate::{DocError, Result};
|
||||
|
||||
/// Most named numbers per point.
|
||||
pub const MAX_COLUMNS: usize = 64;
|
||||
|
||||
/// One named number on every point.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Column {
|
||||
pub name: String,
|
||||
/// Whole numbers (labels, counts): coloured by a palette rather than a ramp.
|
||||
#[serde(default)]
|
||||
pub integer: bool,
|
||||
pub values: Floats,
|
||||
}
|
||||
|
||||
impl Column {
|
||||
/// The smallest and largest finite value.
|
||||
pub fn span(&self) -> Option<[f64; 2]> {
|
||||
let mut it = self.values.0.iter().filter(|v| v.is_finite()).map(|v| f64::from(*v));
|
||||
let first = it.next()?;
|
||||
Some(it.fold([first, first], |[lo, hi], v| [lo.min(v), hi.max(v)]))
|
||||
}
|
||||
}
|
||||
|
||||
/// The complex a cloud's points form: named numbers on the points, and the names of
|
||||
/// whole-numbered ones. Points alone are a complex of dimension 0.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Complex {
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub columns: Vec<Column>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub names: Vec<Names>,
|
||||
}
|
||||
|
||||
/// Most named values of one label.
|
||||
pub const MAX_NAMES: usize = 256;
|
||||
|
||||
/// The names of a label's values.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Names {
|
||||
pub property: String,
|
||||
pub values: Vec<(i32, String)>,
|
||||
}
|
||||
|
||||
impl Names {
|
||||
/// `property: 0 name, 1 another name, -1 none`, or `None` for any other text.
|
||||
pub fn parse(text: &str) -> Option<Names> {
|
||||
let (property, rest) = text.split_once(':')?;
|
||||
let property = property.trim();
|
||||
if property.is_empty() || property.contains(char::is_whitespace) {
|
||||
return None;
|
||||
}
|
||||
let values = rest
|
||||
.split(',')
|
||||
.map(|entry| {
|
||||
let (value, name) = entry.trim().split_once(' ')?;
|
||||
let name = name.trim();
|
||||
(!name.is_empty()).then(|| Some((value.parse::<i32>().ok()?, name.to_string()))).flatten()
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
(!values.is_empty() && values.len() <= MAX_NAMES).then(|| Names { property: property.to_string(), values })
|
||||
}
|
||||
pub fn name(&self, value: i32) -> Option<&str> {
|
||||
self.values.iter().find(|(v, _)| *v == value).map(|(_, n)| n.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl Complex {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.columns.is_empty() && self.names.is_empty()
|
||||
}
|
||||
/// The column named `name`.
|
||||
pub fn column(&self, name: &str) -> Option<&Column> {
|
||||
self.columns.iter().find(|c| c.name == name)
|
||||
}
|
||||
/// The smallest and largest value named `name`.
|
||||
pub fn span(&self, name: &str) -> Option<[f64; 2]> {
|
||||
self.column(name).and_then(Column::span)
|
||||
}
|
||||
/// The names of `property`'s values, when it is a label.
|
||||
pub fn names(&self, property: &str) -> Option<&Names> {
|
||||
self.names.iter().find(|n| n.property == property).filter(|_| self.integer(property))
|
||||
}
|
||||
/// Whether the values named `name` are whole numbers.
|
||||
pub fn integer(&self, name: &str) -> bool {
|
||||
self.column(name).is_some_and(|c| c.integer)
|
||||
}
|
||||
/// Every column has one number per point, the cloud having `points` points.
|
||||
pub fn check(&self, points: usize) -> Result<()> {
|
||||
let bad = |what: String| Err(DocError::Invalid(format!("point cloud properties: {what}")));
|
||||
if self.columns.len() > MAX_COLUMNS {
|
||||
return bad("too many properties".into());
|
||||
}
|
||||
for c in &self.columns {
|
||||
if c.values.0.len() != points {
|
||||
return bad(format!("property `{}` does not have one number per point", c.name));
|
||||
}
|
||||
}
|
||||
if self.names.len() > MAX_COLUMNS || self.names.iter().any(|n| n.values.is_empty() || n.values.len() > MAX_NAMES) {
|
||||
return bad("too many named values".into());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Which points are shown: those whose property lies in a range (both ends included), or, for a
|
||||
/// label, is one of a set of values.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub struct Filter {
|
||||
pub property: String,
|
||||
#[serde(flatten)]
|
||||
pub keep: Keep,
|
||||
}
|
||||
|
||||
/// The values a filter keeps.
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum Keep {
|
||||
Range { range: [f64; 2] },
|
||||
Values { values: Vec<i32> },
|
||||
}
|
||||
|
||||
impl Filter {
|
||||
pub fn range(&self) -> Option<[f64; 2]> {
|
||||
match &self.keep {
|
||||
Keep::Range { range } => Some(*range),
|
||||
Keep::Values { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Numbers, shared between copies of the design.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Floats(pub Arc<[f32]>);
|
||||
|
||||
impl PartialEq for Floats {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
Arc::ptr_eq(&self.0, &other.0) || self.0.iter().map(|v| v.to_bits()).eq(other.0.iter().map(|v| v.to_bits()))
|
||||
}
|
||||
}
|
||||
|
||||
/// The largest base64 text of `n` four-byte words.
|
||||
fn base64_len(n: usize) -> usize {
|
||||
(n * 4).div_ceil(3) * 4 + 16
|
||||
}
|
||||
|
||||
fn words<'de, D: Deserializer<'de>>(d: D, max: usize) -> std::result::Result<Vec<[u8; 4]>, D::Error> {
|
||||
let s = String::deserialize(d)?;
|
||||
if s.len() > base64_len(max) {
|
||||
return Err(serde::de::Error::custom("too many numbers"));
|
||||
}
|
||||
let b = base64_decode(&s).ok_or_else(|| serde::de::Error::custom("numbers are not base64"))?;
|
||||
if !b.len().is_multiple_of(4) {
|
||||
return Err(serde::de::Error::custom("numbers are not whole four-byte words"));
|
||||
}
|
||||
Ok(b.as_chunks::<4>().0.to_vec())
|
||||
}
|
||||
|
||||
impl Serialize for Floats {
|
||||
fn serialize<S: Serializer>(&self, s: S) -> std::result::Result<S::Ok, S::Error> {
|
||||
s.serialize_str(&base64_encode(&self.0.iter().flat_map(|v| v.to_le_bytes()).collect::<Vec<u8>>()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Floats {
|
||||
fn deserialize<D: Deserializer<'de>>(d: D) -> std::result::Result<Self, D::Error> {
|
||||
Ok(Floats(words(d, MAX_POINTS)?.into_iter().map(f32::from_le_bytes).collect()))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn properties_round_trip_and_are_checked_against_the_points() {
|
||||
let complex = Complex {
|
||||
columns: vec![
|
||||
Column { name: "t".into(), integer: false, values: Floats(vec![0.0, 0.5, 1.0].into()) },
|
||||
Column { name: "role".into(), integer: true, values: Floats(vec![0.0, 4.0, 4.0].into()) },
|
||||
],
|
||||
names: Vec::new(),
|
||||
};
|
||||
let back: Complex = serde_json::from_str(&serde_json::to_string(&complex).unwrap()).unwrap();
|
||||
assert_eq!(back, complex);
|
||||
complex.check(3).unwrap();
|
||||
assert!(complex.check(2).is_err(), "three numbers for two points");
|
||||
assert_eq!(complex.span("role"), Some([0.0, 4.0]));
|
||||
assert!(complex.integer("role") && !complex.integer("t") && !complex.integer("nope"));
|
||||
// Named values make a label, and a filter keeps a range or a set of them.
|
||||
let names = Names::parse("role: 0 outer wall, 4 bridge, -1 none").unwrap();
|
||||
assert_eq!((names.name(4), names.name(-1), names.name(2)), (Some("bridge"), Some("none"), None));
|
||||
for text in ["t: seconds since the start", "role 0 wall", ": 0 a", "role: x wall", "role: 0 "] {
|
||||
assert!(Names::parse(text).is_none(), "{text}");
|
||||
}
|
||||
let mut named = complex.clone();
|
||||
named.names = vec![names, Names::parse("t: 0 zero").unwrap()];
|
||||
assert!(named.names("role").is_some() && named.names("t").is_none(), "only whole numbers are labels");
|
||||
let set: Filter = serde_json::from_str(r#"{"property": "role", "values": [0, 4]}"#).unwrap();
|
||||
let range: Filter = serde_json::from_str(r#"{"property": "t", "range": [1, 3]}"#).unwrap();
|
||||
assert_eq!((set.range(), range.range()), (None, Some([1.0, 3.0])));
|
||||
assert_eq!(serde_json::to_value(&set).unwrap(), serde_json::json!({"property": "role", "values": [0, 4]}));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
//! How much of a point cloud lies at each value of one of its properties, over what its filters
|
||||
//! keep: the histograms the Edit Point Cloud card draws in its range tracks, split into the
|
||||
//! colours the view draws, and the values where a label changes along a property, which the
|
||||
//! tracks snap to.
|
||||
//!
|
||||
//! Each point weighs the same, the cloud weighing 1. A range filter keeps the points between its
|
||||
//! ends, as the view does; a filter by values keeps those whose rounded value it holds; the
|
||||
//! colour sorts the points kept into the colours they are drawn in. The values the points kept
|
||||
//! take, from the least to the greatest, are the ramp's automatic range: the colours span exactly
|
||||
//! what is shown.
|
||||
|
||||
use crate::point_cloud::{ColorBy, Filter, Keep, PALETTE, PointCloud, Source};
|
||||
|
||||
/// Most bins of one histogram.
|
||||
pub const MAX_BINS: usize = 8192;
|
||||
|
||||
/// What the histograms need of a cloud's geometry, worked out once for its points.
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct Geometry {
|
||||
/// Each point in the design.
|
||||
world: Vec<[f64; 3]>,
|
||||
}
|
||||
|
||||
impl Geometry {
|
||||
pub fn of(c: &PointCloud) -> Geometry {
|
||||
Geometry { world: (0..c.len()).map(|i| c.world_point(i).map_or([0.0; 3], |p| [p.x, p.y, p.z])).collect() }
|
||||
}
|
||||
}
|
||||
|
||||
/// How a histogram is split by colour, into slots; the last slot holds what has no value to be
|
||||
/// coloured by.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum Colour<'a> {
|
||||
/// One colour.
|
||||
One,
|
||||
/// The ramp over `range` of `property`, in `bands` equal bands; below and above the range
|
||||
/// count with the first and the last.
|
||||
Ramp { property: &'a str, range: [f64; 2], bands: usize },
|
||||
/// The palette of a whole-numbered `property`: a slot per colour of [`PALETTE`], then one
|
||||
/// for negative values.
|
||||
Palette { property: &'a str },
|
||||
}
|
||||
|
||||
impl Colour<'_> {
|
||||
/// How many slots the histogram has.
|
||||
pub fn slots(&self) -> usize {
|
||||
match self {
|
||||
Colour::One => 1,
|
||||
Colour::Ramp { bands, .. } => bands + 1,
|
||||
Colour::Palette { .. } => PALETTE.len() + 2,
|
||||
}
|
||||
}
|
||||
fn property(&self) -> Option<&str> {
|
||||
match self {
|
||||
Colour::One => None,
|
||||
Colour::Ramp { property, .. } | Colour::Palette { property } => Some(property),
|
||||
}
|
||||
}
|
||||
/// How a property's values are cut into bands, and the slot of each band.
|
||||
fn cut(&self) -> Option<Cut> {
|
||||
match *self {
|
||||
Colour::One => None,
|
||||
Colour::Ramp { range: [lo, hi], bands, .. } => Some(Cut::Grid { start: lo, step: (hi - lo) / bands as f64, count: bands + 1 }),
|
||||
Colour::Palette { .. } => Some(INTEGERS),
|
||||
}
|
||||
}
|
||||
fn slot(&self, band: usize) -> usize {
|
||||
match *self {
|
||||
Colour::One => 0,
|
||||
Colour::Ramp { bands, .. } => band.saturating_sub(1).min(bands.saturating_sub(1)),
|
||||
Colour::Palette { .. } => match integer(band) {
|
||||
Some(v) if v >= 0 => v as usize % PALETTE.len(),
|
||||
_ => PALETTE.len(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// How much lies in each bin, by colour slot.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Histogram {
|
||||
pub bins: usize,
|
||||
/// `slots[s][b]`: the measure of slot `s` in bin `b`.
|
||||
pub slots: Vec<Vec<f64>>,
|
||||
/// The least and the greatest value the points kept take, within the axis or not.
|
||||
pub extent: Option<[f64; 2]>,
|
||||
}
|
||||
|
||||
/// Where values are cut into bands, by increasing values.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
enum Cut {
|
||||
/// Below (band 0), within (1, both ends included) and above (2) a range.
|
||||
Range([f64; 2]),
|
||||
/// `count` values `start + k·step`: band 0 lies below the first, band `k` from the `k`th on.
|
||||
Grid { start: f64, step: f64, count: usize },
|
||||
}
|
||||
|
||||
/// The bands of whole numbers: band `k` holds the values rounding to `k - 2³¹`.
|
||||
const INTEGERS: Cut = Cut::Grid { start: 0.5 - 2_147_483_648.0, step: 1.0, count: u32::MAX as usize };
|
||||
|
||||
/// The whole number a band of [`INTEGERS`] holds.
|
||||
fn integer(band: usize) -> Option<i64> {
|
||||
i64::try_from(band).ok().map(|k| k - 2_147_483_648)
|
||||
}
|
||||
|
||||
impl Cut {
|
||||
fn band(&self, v: f64) -> usize {
|
||||
match *self {
|
||||
Cut::Range([a, b]) => usize::from(v >= a) + usize::from(v > b),
|
||||
Cut::Grid { start, step, count } => {
|
||||
if !(v >= start) {
|
||||
return 0;
|
||||
}
|
||||
(((v - start) / step).floor() as usize).saturating_add(1).min(count)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A filter as a cut and the bands it keeps.
|
||||
struct Kept<'a> {
|
||||
cut: Cut,
|
||||
values: Option<&'a [i32]>,
|
||||
}
|
||||
|
||||
impl Kept<'_> {
|
||||
fn of(f: &Filter) -> Kept<'_> {
|
||||
match &f.keep {
|
||||
Keep::Range { range } => Kept { cut: Cut::Range(*range), values: None },
|
||||
Keep::Values { values } => Kept { cut: INTEGERS, values: Some(values) },
|
||||
}
|
||||
}
|
||||
fn keeps(&self, v: f64) -> bool {
|
||||
let band = self.cut.band(v);
|
||||
match self.values {
|
||||
None => band == 1,
|
||||
Some(values) => integer(band).is_some_and(|v| values.iter().any(|k| i64::from(*k) == v)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The value of `s` at point `i`.
|
||||
fn value(s: Source, i: usize, world: &[[f64; 3]]) -> f64 {
|
||||
match s {
|
||||
Source::Coordinate(k) => world.get(i).and_then(|p| p.get(k)).copied().unwrap_or(f64::NAN),
|
||||
Source::Column(v) => v.get(i).map_or(f64::NAN, |x| f64::from(*x)),
|
||||
}
|
||||
}
|
||||
|
||||
/// How much of the cloud lies in each of `bins` bins over `axis` of `property`, by `colour`,
|
||||
/// within every one of `filters`; `None` for an axis or a number of bins it can't have.
|
||||
pub fn histogram(
|
||||
c: &PointCloud,
|
||||
g: &Geometry,
|
||||
property: &str,
|
||||
axis: [f64; 2],
|
||||
bins: usize,
|
||||
colour: &Colour,
|
||||
filters: &[Filter],
|
||||
) -> Option<Histogram> {
|
||||
if !(axis[0].is_finite() && axis[1].is_finite() && axis[1] > axis[0]) || bins == 0 || bins > MAX_BINS {
|
||||
return None;
|
||||
}
|
||||
if let Colour::Ramp { range: [lo, hi], bands, .. } = *colour
|
||||
&& !(hi > lo && bands > 0 && bands <= MAX_BINS)
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let slots = colour.slots();
|
||||
let mut out = vec![vec![0.0; bins]; slots];
|
||||
let mut extent = None;
|
||||
let Some(p) = c.source(property) else { return Some(Histogram { bins, slots: out, extent }) };
|
||||
// A point is not filtered by a property the cloud doesn't have, as in the view.
|
||||
let kept: Vec<(Kept, Source)> = filters.iter().filter_map(|f| Some((Kept::of(f), c.source(&f.property)?))).collect();
|
||||
let coloured = colour.property().and_then(|n| c.source(n));
|
||||
let (colour_cut, plain) = (colour.cut(), slots - 1);
|
||||
let m = 1.0 / g.world.len().max(1) as f64;
|
||||
let width = (axis[1] - axis[0]) / bins as f64;
|
||||
for i in 0..g.world.len() {
|
||||
if !kept.iter().all(|(k, s)| k.keeps(value(*s, i, &g.world))) {
|
||||
continue;
|
||||
}
|
||||
let v = value(p, i, &g.world);
|
||||
if !v.is_finite() {
|
||||
continue;
|
||||
}
|
||||
extent = Some(extent.map_or([v, v], |[lo, hi]: [f64; 2]| [lo.min(v), hi.max(v)]));
|
||||
if !(v >= axis[0] && v <= axis[1]) {
|
||||
continue;
|
||||
}
|
||||
let slot = match (colour_cut, coloured) {
|
||||
(Some(cut), Some(s)) => colour.slot(cut.band(value(s, i, &g.world))),
|
||||
(Some(_), None) => plain,
|
||||
(None, _) => 0,
|
||||
};
|
||||
// The last bin holds the axis' upper end too.
|
||||
let bin = (((v - axis[0]) / width).floor() as usize).min(bins - 1);
|
||||
if let Some(b) = out.get_mut(slot).and_then(|s| s.get_mut(bin)) {
|
||||
*b += m;
|
||||
}
|
||||
}
|
||||
Some(Histogram { bins, slots: out, extent })
|
||||
}
|
||||
|
||||
/// A range for a ramp from the values it spans: a single value gets one unit around it.
|
||||
pub fn ramp_range([lo, hi]: [f64; 2]) -> [f64; 2] {
|
||||
if hi > lo { [lo, hi] } else { [lo - 0.5, lo + 0.5] }
|
||||
}
|
||||
|
||||
/// The ramp's range: the one set; else, coloured by a property, exactly the values it takes over
|
||||
/// what `filters` keep (the cloud's own bound, [`PointCloud::color_range`], when nothing is
|
||||
/// kept); coloured by height, the cloud's own (its points but the highest and lowest few).
|
||||
pub fn color_range(c: &PointCloud, g: &Geometry, filters: &[Filter]) -> Option<[f64; 2]> {
|
||||
color_range_by(c, |property, axis| histogram(c, g, property, axis, 1, &Colour::One, filters).and_then(|h| h.extent))
|
||||
}
|
||||
|
||||
/// [`color_range`], with the values the coloured property takes over what is kept given by
|
||||
/// `extent` (of the property and an axis over its span): worked out elsewhere, or not yet.
|
||||
pub fn color_range_by(c: &PointCloud, extent: impl FnOnce(&str, [f64; 2]) -> Option<[f64; 2]>) -> Option<[f64; 2]> {
|
||||
let property = c.colored_property()?;
|
||||
if c.height_range.is_some() || c.color_by != ColorBy::Property {
|
||||
return c.color_range();
|
||||
}
|
||||
let axis = ramp_range(c.span(property)?);
|
||||
extent(property, axis).map(ramp_range).or_else(|| c.color_range())
|
||||
}
|
||||
|
||||
/// The values of `property` where the whole-numbered `label` changes, point after point in order
|
||||
/// of `property`, lowest first.
|
||||
pub fn label_changes(c: &PointCloud, g: &Geometry, label: &str, property: &str) -> Vec<f64> {
|
||||
let (Some(p), Some(l)) = (c.source(property), c.source(label)) else { return Vec::new() };
|
||||
let mut at: Vec<(f64, i64)> = (0..g.world.len())
|
||||
.filter_map(|i| {
|
||||
let (v, l) = (value(p, i, &g.world), value(l, i, &g.world));
|
||||
v.is_finite().then(|| (v, if l.is_finite() { l.round() as i64 } else { i64::MIN }))
|
||||
})
|
||||
.collect();
|
||||
at.sort_by(|a, b| a.0.total_cmp(&b.0));
|
||||
let mut out: Vec<f64> = at.windows(2).filter(|w| w[0].1 != w[1].1).map(|w| w[1].0).collect();
|
||||
out.dedup();
|
||||
out
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "point_cloud_distribution_tests.rs"]
|
||||
mod tests;
|
||||
@@ -0,0 +1,125 @@
|
||||
use solidcraft_geom::Vec3;
|
||||
|
||||
use super::*;
|
||||
use crate::IDENTITY;
|
||||
use crate::point_cloud::{ColorBy, Colors, Column, Complex, Floats, Points};
|
||||
|
||||
/// A cloud of `points` with `columns` on them.
|
||||
fn cloud(points: &[[f32; 3]], columns: Vec<Column>) -> PointCloud {
|
||||
PointCloud {
|
||||
id: 1,
|
||||
name: "c".into(),
|
||||
file: String::new(),
|
||||
origin: Vec3::new(0.0, 0.0, 0.0),
|
||||
points: Points::new(points.iter().flatten().copied().collect::<Vec<f32>>().into()),
|
||||
colors: Colors::default(),
|
||||
source_points: points.len() as u64,
|
||||
units: "mm".into(),
|
||||
transform: IDENTITY,
|
||||
point_size: 2.0,
|
||||
color_by: ColorBy::File,
|
||||
color: None,
|
||||
height_range: None,
|
||||
visible: true,
|
||||
complex: Complex { columns, names: Vec::new() },
|
||||
color_property: None,
|
||||
filters: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn column(name: &str, integer: bool, values: &[f32]) -> Column {
|
||||
Column { name: name.into(), integer, values: Floats(values.to_vec().into()) }
|
||||
}
|
||||
|
||||
fn range(property: &str, range: [f64; 2]) -> Filter {
|
||||
Filter { property: property.into(), keep: Keep::Range { range } }
|
||||
}
|
||||
|
||||
fn close(a: &[f64], b: &[f64]) -> bool {
|
||||
a.len() == b.len() && a.iter().zip(b).all(|(x, y)| (x - y).abs() < 1e-9)
|
||||
}
|
||||
|
||||
/// Ten points along x, `t` the same as x.
|
||||
fn row() -> PointCloud {
|
||||
let points: Vec<[f32; 3]> = (0..10).map(|i| [i as f32 + 0.5, 0.0, 0.0]).collect();
|
||||
let t: Vec<f32> = points.iter().map(|p| p[0]).collect();
|
||||
cloud(&points, vec![column("t", false, &t)])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn each_point_weighs_alike_and_a_range_keeps_those_within_it() {
|
||||
let c = row();
|
||||
let g = Geometry::of(&c);
|
||||
let all = histogram(&c, &g, "t", [0.0, 10.0], 5, &Colour::One, &[]).unwrap();
|
||||
assert!(close(&all.slots[0], &[0.2; 5]));
|
||||
// Kept from t = 2 to 5: three points, ends included.
|
||||
let kept = histogram(&c, &g, "t", [0.0, 10.0], 5, &Colour::One, &[range("t", [2.0, 5.0])]).unwrap();
|
||||
assert!(close(&kept.slots[0], &[0.0, 0.2, 0.1, 0.0, 0.0]));
|
||||
// Filtered by another property: x from 0 to 4 keeps t from 0 to 4.
|
||||
let by_x = histogram(&c, &g, "t", [0.0, 10.0], 5, &Colour::One, &[range("x", [0.0, 4.0])]).unwrap();
|
||||
assert!(close(&by_x.slots[0], &[0.2, 0.2, 0.0, 0.0, 0.0]));
|
||||
// A filter on a property the cloud doesn't have keeps everything, as in the view.
|
||||
assert_eq!(histogram(&c, &g, "t", [0.0, 10.0], 5, &Colour::One, &[range("nope", [0.0, 1.0])]), Some(all));
|
||||
// An axis or a number of bins it can't have.
|
||||
for (axis, bins) in [([1.0, 1.0], 4), ([0.0, f64::NAN], 4), ([0.0, 1.0], 0), ([0.0, 1.0], MAX_BINS + 1)] {
|
||||
assert!(histogram(&c, &g, "t", axis, bins, &Colour::One, &[]).is_none());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn colours_split_what_is_kept() {
|
||||
// Four points, roles 0, 3, 3 and -1, t from 0 to 3.
|
||||
let c = cloud(
|
||||
&[[0.0; 3], [1.0, 0.0, 0.0], [2.0, 0.0, 0.0], [3.0, 0.0, 0.0]],
|
||||
vec![column("t", false, &[0.0, 1.0, 2.0, 3.0]), column("role", true, &[0.0, 3.0, 3.0, -1.0])],
|
||||
);
|
||||
let g = Geometry::of(&c);
|
||||
let colour = Colour::Palette { property: "role" };
|
||||
let h = histogram(&c, &g, "t", [0.0, 4.0], 4, &colour, &[]).unwrap();
|
||||
assert_eq!(h.slots.len(), colour.slots());
|
||||
assert!(close(&h.slots[0], &[0.25, 0.0, 0.0, 0.0]));
|
||||
assert!(close(&h.slots[3], &[0.0, 0.25, 0.25, 0.0]));
|
||||
assert!(close(&h.slots[PALETTE.len()], &[0.0, 0.0, 0.0, 0.25]), "a negative label");
|
||||
// A filter by values keeps role 3 only.
|
||||
let three = Filter { property: "role".into(), keep: Keep::Values { values: vec![3] } };
|
||||
let kept = histogram(&c, &g, "t", [0.0, 4.0], 4, &colour, &[three]).unwrap();
|
||||
let total: f64 = kept.slots.iter().flatten().sum();
|
||||
assert!((total - 0.5).abs() < 1e-9 && close(&kept.slots[3], &h.slots[3]));
|
||||
// A ramp over t in two bands, and coloured by a property the cloud doesn't have: plain.
|
||||
let ramp = Colour::Ramp { property: "t", range: [0.0, 4.0], bands: 2 };
|
||||
let r = histogram(&c, &g, "t", [0.0, 4.0], 4, &ramp, &[]).unwrap();
|
||||
assert!(close(&r.slots[0], &[0.25, 0.25, 0.0, 0.0]) && close(&r.slots[1], &[0.0, 0.0, 0.25, 0.25]));
|
||||
let none = histogram(&c, &g, "t", [0.0, 4.0], 4, &Colour::Palette { property: "nope" }, &[]).unwrap();
|
||||
assert!(close(&none.slots[PALETTE.len() + 1], &[0.25; 4]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn labels_change_where_the_next_point_has_another() {
|
||||
// Six points in order of t, layers 0 0 1 1 2 2.
|
||||
let points: Vec<[f32; 3]> = (0..6).map(|i| [i as f32, 0.0, 0.0]).collect();
|
||||
let c = cloud(&points, vec![column("t", false, &[0.0, 1.0, 2.0, 3.0, 4.0, 5.0]), column("layer", true, &[0.0, 0.0, 1.0, 1.0, 2.0, 2.0])]);
|
||||
let g = Geometry::of(&c);
|
||||
assert_eq!(label_changes(&c, &g, "layer", "t"), vec![2.0, 4.0]);
|
||||
assert!(label_changes(&c, &g, "nope", "t").is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_automatic_range_is_what_every_filter_keeps() {
|
||||
// Filtered by x from 2 to 4, coloured by t: the range is what is kept of t, though no filter
|
||||
// is on t (its span within filters on t would be all of it).
|
||||
let mut c = cloud(&[[0.0, 0.0, 0.0], [2.0, 0.0, 0.0], [4.0, 0.0, 0.0], [20.0, 0.0, 0.0]], vec![column("t", false, &[0.0, 3.0, 5.0, 7.0])]);
|
||||
c.color_by = ColorBy::Property;
|
||||
c.color_property = Some("t".into());
|
||||
let g = Geometry::of(&c);
|
||||
let x = [range("x", [2.0, 4.0])];
|
||||
assert_eq!(c.color_range(), Some([0.0, 7.0]));
|
||||
assert_eq!(color_range(&c, &g, &x), Some([3.0, 5.0]));
|
||||
// The point at x = 20 alone: one value, one unit wide.
|
||||
assert_eq!(color_range(&c, &g, &[range("x", [19.0, 21.0])]), Some([6.5, 7.5]));
|
||||
// Nothing kept: the cloud's own bound; a range set is kept as it is.
|
||||
assert_eq!(color_range(&c, &g, &[range("x", [50.0, 60.0])]), Some([0.0, 7.0]));
|
||||
c.height_range = Some([1.0, 2.0]);
|
||||
assert_eq!(color_range(&c, &g, &x), Some([1.0, 2.0]));
|
||||
let h = histogram(&c, &g, "t", [0.0, 1.0], 4, &Colour::One, &x).unwrap();
|
||||
assert_eq!(h.extent, Some([3.0, 5.0]), "the extent reaches past the axis");
|
||||
}
|
||||