@things-factory/figure-ui 10.1.44 → 10.1.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/client/modeller/figure-v3-links.ts +394 -0
  2. package/client/modeller/modeller-route.ts +6 -21
  3. package/client/modeller/v3-editor.ts +47 -5
  4. package/client/modeller/v3-gizmo.ts +13 -2
  5. package/client/modeller/v3-links.ts +170 -0
  6. package/client/pages/figure-v3-modeller-page.ts +2 -5
  7. package/client/route.ts +2 -6
  8. package/dist-client/modeller/figure-v3-links.d.ts +47 -0
  9. package/dist-client/modeller/figure-v3-links.js +379 -0
  10. package/dist-client/modeller/figure-v3-links.js.map +1 -0
  11. package/dist-client/modeller/modeller-route.d.ts +4 -11
  12. package/dist-client/modeller/modeller-route.js +5 -22
  13. package/dist-client/modeller/modeller-route.js.map +1 -1
  14. package/dist-client/modeller/v3-editor.d.ts +5 -0
  15. package/dist-client/modeller/v3-editor.js +49 -4
  16. package/dist-client/modeller/v3-editor.js.map +1 -1
  17. package/dist-client/modeller/v3-gizmo.js +11 -1
  18. package/dist-client/modeller/v3-gizmo.js.map +1 -1
  19. package/dist-client/modeller/v3-links.d.ts +67 -0
  20. package/dist-client/modeller/v3-links.js +141 -0
  21. package/dist-client/modeller/v3-links.js.map +1 -0
  22. package/dist-client/pages/figure-v3-modeller-page.d.ts +2 -5
  23. package/dist-client/pages/figure-v3-modeller-page.js +2 -5
  24. package/dist-client/pages/figure-v3-modeller-page.js.map +1 -1
  25. package/dist-client/route.d.ts +1 -1
  26. package/dist-client/route.js +2 -5
  27. package/dist-client/route.js.map +1 -1
  28. package/dist-client/tsconfig.scratch-fm.tsbuildinfo +1 -0
  29. package/dist-client/tsconfig.tsbuildinfo +1 -1
  30. package/package.json +4 -4
  31. package/test/ai-proposal-contract.test.ts +0 -88
  32. package/test/figure-source.test.ts +0 -102
  33. package/test/i18n-prefix-guard.test.ts +0 -24
  34. package/test/modeller-route.test.ts +14 -25
  35. package/test/part-edits.test.ts +0 -7
  36. package/test/scene-budget.test.ts +0 -7
  37. package/test/v3-gizmo.test.ts +10 -0
  38. package/test/v3-links.test.ts +163 -0
  39. package/things-factory.config.js +2 -5
  40. package/translations/en.json +21 -1
  41. package/translations/ja.json +21 -1
  42. package/translations/ko.json +21 -1
  43. package/translations/ms.json +21 -1
  44. package/translations/zh.json +21 -1
  45. package/client/modeller/angle-dial.ts +0 -70
  46. package/client/modeller/base-box.ts +0 -175
  47. package/client/modeller/figure-animations.ts +0 -1249
  48. package/client/modeller/figure-canvas.ts +0 -567
  49. package/client/modeller/figure-capabilities.ts +0 -379
  50. package/client/modeller/figure-inspector.ts +0 -2208
  51. package/client/modeller/figure-parts.ts +0 -479
  52. package/client/modeller/figure-preview.ts +0 -598
  53. package/client/modeller/figure-report.ts +0 -966
  54. package/client/modeller/figure-settings.ts +0 -328
  55. package/client/modeller/figure-side.ts +0 -272
  56. package/client/modeller/figure-thumbnail.ts +0 -123
  57. package/client/modeller/figure-view.ts +0 -152
  58. package/client/modeller/joint-edits.ts +0 -262
  59. package/client/modeller/joint-gizmo.ts +0 -180
  60. package/client/modeller/maturity.ts +0 -288
  61. package/client/modeller/new-figure-entry.ts +0 -4
  62. package/client/modeller/pose-defaults.ts +0 -67
  63. package/client/pages/figure-modeller-page.ts +0 -2082
  64. package/dist-client/modeller/angle-dial.d.ts +0 -32
  65. package/dist-client/modeller/angle-dial.js +0 -41
  66. package/dist-client/modeller/angle-dial.js.map +0 -1
  67. package/dist-client/modeller/base-box.d.ts +0 -71
  68. package/dist-client/modeller/base-box.js +0 -110
  69. package/dist-client/modeller/base-box.js.map +0 -1
  70. package/dist-client/modeller/figure-animations.d.ts +0 -159
  71. package/dist-client/modeller/figure-animations.js +0 -1132
  72. package/dist-client/modeller/figure-animations.js.map +0 -1
  73. package/dist-client/modeller/figure-canvas.d.ts +0 -150
  74. package/dist-client/modeller/figure-canvas.js +0 -506
  75. package/dist-client/modeller/figure-canvas.js.map +0 -1
  76. package/dist-client/modeller/figure-capabilities.d.ts +0 -42
  77. package/dist-client/modeller/figure-capabilities.js +0 -349
  78. package/dist-client/modeller/figure-capabilities.js.map +0 -1
  79. package/dist-client/modeller/figure-inspector.d.ts +0 -329
  80. package/dist-client/modeller/figure-inspector.js +0 -2095
  81. package/dist-client/modeller/figure-inspector.js.map +0 -1
  82. package/dist-client/modeller/figure-parts.d.ts +0 -64
  83. package/dist-client/modeller/figure-parts.js +0 -478
  84. package/dist-client/modeller/figure-parts.js.map +0 -1
  85. package/dist-client/modeller/figure-preview.d.ts +0 -138
  86. package/dist-client/modeller/figure-preview.js +0 -549
  87. package/dist-client/modeller/figure-preview.js.map +0 -1
  88. package/dist-client/modeller/figure-report.d.ts +0 -165
  89. package/dist-client/modeller/figure-report.js +0 -952
  90. package/dist-client/modeller/figure-report.js.map +0 -1
  91. package/dist-client/modeller/figure-settings.d.ts +0 -39
  92. package/dist-client/modeller/figure-settings.js +0 -317
  93. package/dist-client/modeller/figure-settings.js.map +0 -1
  94. package/dist-client/modeller/figure-side.d.ts +0 -78
  95. package/dist-client/modeller/figure-side.js +0 -317
  96. package/dist-client/modeller/figure-side.js.map +0 -1
  97. package/dist-client/modeller/figure-thumbnail.d.ts +0 -3
  98. package/dist-client/modeller/figure-thumbnail.js +0 -95
  99. package/dist-client/modeller/figure-thumbnail.js.map +0 -1
  100. package/dist-client/modeller/figure-view.d.ts +0 -118
  101. package/dist-client/modeller/figure-view.js +0 -78
  102. package/dist-client/modeller/figure-view.js.map +0 -1
  103. package/dist-client/modeller/joint-edits.d.ts +0 -49
  104. package/dist-client/modeller/joint-edits.js +0 -223
  105. package/dist-client/modeller/joint-edits.js.map +0 -1
  106. package/dist-client/modeller/joint-gizmo.d.ts +0 -34
  107. package/dist-client/modeller/joint-gizmo.js +0 -158
  108. package/dist-client/modeller/joint-gizmo.js.map +0 -1
  109. package/dist-client/modeller/maturity.d.ts +0 -55
  110. package/dist-client/modeller/maturity.js +0 -212
  111. package/dist-client/modeller/maturity.js.map +0 -1
  112. package/dist-client/modeller/new-figure-entry.d.ts +0 -2
  113. package/dist-client/modeller/new-figure-entry.js +0 -5
  114. package/dist-client/modeller/new-figure-entry.js.map +0 -1
  115. package/dist-client/modeller/pose-defaults.d.ts +0 -9
  116. package/dist-client/modeller/pose-defaults.js +0 -35
  117. package/dist-client/modeller/pose-defaults.js.map +0 -1
  118. package/dist-client/pages/figure-modeller-page.d.ts +0 -419
  119. package/dist-client/pages/figure-modeller-page.js +0 -2060
  120. package/dist-client/pages/figure-modeller-page.js.map +0 -1
  121. package/test/angle-dial.test.ts +0 -78
  122. package/test/base-box.test.ts +0 -235
  123. package/test/joint-edits.test.ts +0 -165
  124. package/test/joint-gizmo.test.ts +0 -174
  125. package/test/joint-needle.test.ts +0 -162
  126. package/test/modeller-undo-redo.test.ts +0 -33
  127. package/test/new-figure-entry.test.ts +0 -15
  128. package/test/pose-defaults.test.ts +0 -71
  129. package/test/preview-board-depth.test.ts +0 -27
@@ -14,6 +14,7 @@
14
14
  "figure.button.discard": "discard",
15
15
  "figure.button.duplicate-part": "duplicate",
16
16
  "figure.button.fit-base-to-parts": "部品に合わせる",
17
+ "figure.button.fix-position": "ここに固定",
17
18
  "figure.button.mirror-x": "mirror X",
18
19
  "figure.button.mirror-z": "mirror Z",
19
20
  "figure.button.move-part-down": "move down",
@@ -35,13 +36,18 @@
35
36
  "figure.button.snap": "snap",
36
37
  "figure.button.take-n-changes": "apply {n}",
37
38
  "figure.label.declared-space": "空間宣言",
39
+ "figure.label.follows-expression": "式で決まる",
38
40
  "figure.label.gizmo-rotate": "回転",
39
41
  "figure.label.gizmo-scale": "サイズ",
40
42
  "figure.label.gizmo-translate": "移動",
43
+ "figure.label.position-worked-out": "図形のサイズに合わせて動く",
41
44
  "figure.label.primitive-rounded-box": "角丸ボックス",
42
45
  "figure.text.catalog-needs-a-save": "保存した後に設定できます。",
43
46
  "figure.text.declared-space-declared": "部品から宣言しました。",
44
47
  "figure.text.declared-space-none": "まだ宣言していません。",
48
+ "figure.text.fasten-would-loop": "その部品はすでにこの部品に取り付けられているため、逆向きに取り付けられません。",
49
+ "figure.text.follow-would-loop": "その寸法はすでにこの部品に追従しているため、互いに追従させられません。",
50
+ "figure.text.links-need-a-box": "サイズ追従は箱形、取り付けは箱形と円柱の部品で使えます。",
45
51
  "figure.text.mounting-face-needs-space": "先に空間を宣言すると選べます。",
46
52
  "figure.text.part-is-referenced": "'{part}' には他の部品が取り付けられているか、そのサイズに従っているため削除できません。先にその連結を外してください。",
47
53
  "figure.text.part-name-invalid": "'{name}' は部品名に使えません。英字で始め、英字・数字・-・_ のみ使えます。",
@@ -559,5 +565,19 @@
559
565
  "figure.button.keep-changed-appearance": "調整したモデル幅で公開",
560
566
  "figure.button.restore-released-base": "以前のモデル幅に戻す",
561
567
  "figure.text.appearance-choice-explained": "戻すと X と Z を直前の公開値に戻し、Y とほかの編集はそのまま残します。調整した幅で公開すると、今のモデルの外形を残します。",
562
- "figure.text.choose-appearance-change": "調整したモデル幅の扱いを選んでください"
568
+ "figure.text.choose-appearance-change": "調整したモデル幅の扱いを選んでください",
569
+ "figure.label.places": "置き場所",
570
+ "figure.text.places-need-a-box": "置き場所は箱形の部品の面に置きます。",
571
+ "figure.label.place-grip": "つかむ場所",
572
+ "figure.label.place-seat": "載せる場所",
573
+ "figure.label.place-holds": "{count}個まで",
574
+ "figure.button.remove-place": "置き場所を削除",
575
+ "figure.text.place-explained": "ボード上で物をこの部品のどの面に載せるか、つかむかを決めます。部品が動くと物も一緒に動きます。",
576
+ "figure.text.place-needs-holding": "この図形は物を保持すると宣言していないため、置き場所を作ってもボードは物を渡しません。",
577
+ "figure.button.declare-holding": "物を保持する図形にする",
578
+ "figure.label.place-name": "名前",
579
+ "figure.label.place-accepts": "受け取る種類",
580
+ "figure.label.place-capacity": "最大個数",
581
+ "figure.text.place-accepts-needed": "受け取る種類を一つ以上、カンマ区切りで入力してください。",
582
+ "figure.button.add-place": "置き場所を追加"
563
583
  }
@@ -14,6 +14,7 @@
14
14
  "figure.button.discard": "취소",
15
15
  "figure.button.duplicate-part": "복제",
16
16
  "figure.button.fit-base-to-parts": "부품에 맞추기",
17
+ "figure.button.fix-position": "여기에 고정",
17
18
  "figure.button.mirror-x": "X 대칭",
18
19
  "figure.button.mirror-z": "Z 대칭",
19
20
  "figure.button.move-part-down": "아래로",
@@ -37,13 +38,18 @@
37
38
  "figure.button.snap": "눈금에",
38
39
  "figure.button.take-n-changes": "{n}개 적용",
39
40
  "figure.label.declared-space": "공간 선언",
41
+ "figure.label.follows-expression": "식으로 정해짐",
40
42
  "figure.label.gizmo-rotate": "돌리기",
41
43
  "figure.label.gizmo-scale": "크기",
42
44
  "figure.label.gizmo-translate": "옮기기",
45
+ "figure.label.position-worked-out": "도형 크기를 따라 움직임",
43
46
  "figure.label.primitive-rounded-box": "둥근 상자",
44
47
  "figure.text.catalog-needs-a-save": "저장한 뒤에 정할 수 있습니다.",
45
48
  "figure.text.declared-space-declared": "부품으로 선언했습니다.",
46
49
  "figure.text.declared-space-none": "아직 선언하지 않았습니다.",
50
+ "figure.text.fasten-would-loop": "그 부품은 이미 이 부품에 붙어 있어서 거꾸로 붙일 수 없습니다.",
51
+ "figure.text.follow-would-loop": "그 치수는 이미 이 부품을 따르고 있어서 서로 따르게 할 수 없습니다.",
52
+ "figure.text.links-need-a-box": "크기 따르기는 상자 모양, 붙이기는 상자·원기둥 부품에서 씁니다.",
47
53
  "figure.text.mounting-face-needs-space": "공간을 먼저 선언해야 고를 수 있습니다.",
48
54
  "figure.text.part-is-referenced": "'{part}' 에 다른 부품이 붙어 있거나 그 크기를 따르고 있어 지울 수 없습니다. 그 연결을 먼저 푸세요.",
49
55
  "figure.text.part-name-invalid": "'{name}' 은 부품 이름으로 쓸 수 없습니다. 영문자로 시작하고 영문자·숫자·-·_ 만 씁니다.",
@@ -559,5 +565,19 @@
559
565
  "figure.label.state-inputs": "상태 입력",
560
566
  "figure.label.design-inputs": "설계 입력",
561
567
  "figure.text.release-blocked": "발행이 막힙니다 — {count}건",
562
- "figure.text.release-ready": "발행할 수 있습니다"
568
+ "figure.text.release-ready": "발행할 수 있습니다",
569
+ "figure.label.places": "자리",
570
+ "figure.text.places-need-a-box": "자리는 상자 모양 부품의 면에 둡니다.",
571
+ "figure.label.place-grip": "집는 자리",
572
+ "figure.label.place-seat": "놓는 자리",
573
+ "figure.label.place-holds": "{count}개까지",
574
+ "figure.button.remove-place": "자리 없애기",
575
+ "figure.text.place-explained": "보드에서 물건을 이 부품의 어느 면에 놓거나 집을지 정합니다. 부품이 움직이면 물건도 따라갑니다.",
576
+ "figure.text.place-needs-holding": "이 도형은 물건을 담는다고 선언하지 않아서, 자리를 만들어도 보드가 여기에 물건을 넘기지 않습니다.",
577
+ "figure.button.declare-holding": "물건을 담는 도형으로",
578
+ "figure.label.place-name": "이름",
579
+ "figure.label.place-accepts": "받는 종류",
580
+ "figure.label.place-capacity": "몇 개까지",
581
+ "figure.text.place-accepts-needed": "받는 종류를 하나 이상 적어야 자리를 만들 수 있습니다. 쉼표로 나눕니다.",
582
+ "figure.button.add-place": "자리 추가"
563
583
  }
@@ -14,6 +14,7 @@
14
14
  "figure.button.discard": "discard",
15
15
  "figure.button.duplicate-part": "duplicate",
16
16
  "figure.button.fit-base-to-parts": "muatkan pada bahagian",
17
+ "figure.button.fix-position": "tetapkan di sini",
17
18
  "figure.button.mirror-x": "mirror X",
18
19
  "figure.button.mirror-z": "mirror Z",
19
20
  "figure.button.move-part-down": "move down",
@@ -35,13 +36,18 @@
35
36
  "figure.button.snap": "snap",
36
37
  "figure.button.take-n-changes": "apply {n}",
37
38
  "figure.label.declared-space": "ruang yang diisytiharkan",
39
+ "figure.label.follows-expression": "ditetapkan oleh ungkapan",
38
40
  "figure.label.gizmo-rotate": "putar",
39
41
  "figure.label.gizmo-scale": "saiz",
40
42
  "figure.label.gizmo-translate": "alih",
43
+ "figure.label.position-worked-out": "bergerak mengikut saiz bentuk",
41
44
  "figure.label.primitive-rounded-box": "kotak bucu bulat",
42
45
  "figure.text.catalog-needs-a-save": "boleh ditetapkan selepas disimpan.",
43
46
  "figure.text.declared-space-declared": "diisytiharkan daripada bahagian.",
44
47
  "figure.text.declared-space-none": "belum diisytiharkan.",
48
+ "figure.text.fasten-would-loop": "bahagian itu sudah dipasang pada bahagian ini, jadi ia tidak boleh dipasang sebaliknya.",
49
+ "figure.text.follow-would-loop": "dimensi itu sudah mengikut bahagian ini, jadi kedua-duanya tidak boleh saling mengikut.",
50
+ "figure.text.links-need-a-box": "ikut saiz untuk bahagian berbentuk kotak, pasangan untuk kotak dan silinder.",
45
51
  "figure.text.mounting-face-needs-space": "isytiharkan ruang dahulu untuk memilih.",
46
52
  "figure.text.part-is-referenced": "'{part}' tidak boleh dipadam: bahagian lain dipasang padanya atau mengikut saiznya. Leraikan pautan itu dahulu.",
47
53
  "figure.text.part-name-invalid": "'{name}' tidak boleh menjadi nama bahagian. Mulakan dengan huruf dan gunakan huruf, digit, - dan _.",
@@ -559,5 +565,19 @@
559
565
  "figure.button.keep-changed-appearance": "terbitkan dengan lebar model yang dilaraskan",
560
566
  "figure.button.restore-released-base": "pulihkan lebar model sebelumnya",
561
567
  "figure.text.appearance-choice-explained": "Pulihkan mengembalikan X dan Z kepada nilai terbitan sebelumnya dan mengekalkan Y serta semua suntingan lain. Menerbitkan dengan lebar yang dilaraskan mengekalkan garis luar model semasa.",
562
- "figure.text.choose-appearance-change": "pilih cara mengendalikan lebar model yang dilaraskan"
568
+ "figure.text.choose-appearance-change": "pilih cara mengendalikan lebar model yang dilaraskan",
569
+ "figure.label.places": "Tempat",
570
+ "figure.text.places-need-a-box": "Tempat diletakkan pada muka bahagian berbentuk kotak.",
571
+ "figure.label.place-grip": "Tempat cengkam",
572
+ "figure.label.place-seat": "Tempat letak",
573
+ "figure.label.place-holds": "sehingga {count}",
574
+ "figure.button.remove-place": "Buang tempat",
575
+ "figure.text.place-explained": "Tentukan muka bahagian ini tempat papan meletakkan atau memegang barang. Apabila bahagian bergerak, barang ikut bergerak.",
576
+ "figure.text.place-needs-holding": "Rajah ini tidak mengisytiharkan bahawa ia memegang barang, jadi papan tidak menyerahkan apa-apa ke tempatnya.",
577
+ "figure.button.declare-holding": "Jadikan ia memegang barang",
578
+ "figure.label.place-name": "Nama",
579
+ "figure.label.place-accepts": "Jenis diterima",
580
+ "figure.label.place-capacity": "Berapa banyak",
581
+ "figure.text.place-accepts-needed": "Namakan sekurang-kurangnya satu jenis yang diterima, dipisahkan dengan koma.",
582
+ "figure.button.add-place": "Tambah tempat"
563
583
  }
@@ -14,6 +14,7 @@
14
14
  "figure.button.discard": "discard",
15
15
  "figure.button.duplicate-part": "duplicate",
16
16
  "figure.button.fit-base-to-parts": "适配部件",
17
+ "figure.button.fix-position": "固定在此",
17
18
  "figure.button.mirror-x": "mirror X",
18
19
  "figure.button.mirror-z": "mirror Z",
19
20
  "figure.button.move-part-down": "move down",
@@ -35,13 +36,18 @@
35
36
  "figure.button.snap": "snap",
36
37
  "figure.button.take-n-changes": "apply {n}",
37
38
  "figure.label.declared-space": "空间声明",
39
+ "figure.label.follows-expression": "由表达式决定",
38
40
  "figure.label.gizmo-rotate": "旋转",
39
41
  "figure.label.gizmo-scale": "尺寸",
40
42
  "figure.label.gizmo-translate": "移动",
43
+ "figure.label.position-worked-out": "随图形尺寸移动",
41
44
  "figure.label.primitive-rounded-box": "圆角盒",
42
45
  "figure.text.catalog-needs-a-save": "保存后即可设置。",
43
46
  "figure.text.declared-space-declared": "已根据部件声明。",
44
47
  "figure.text.declared-space-none": "尚未声明。",
48
+ "figure.text.fasten-would-loop": "该部件已固定在此部件上,不能反向固定。",
49
+ "figure.text.follow-would-loop": "该尺寸已跟随此部件,二者不能互相跟随。",
50
+ "figure.text.links-need-a-box": "尺寸跟随适用于盒形部件,固定适用于盒形和圆柱部件。",
45
51
  "figure.text.mounting-face-needs-space": "请先声明空间,然后才能选择。",
46
52
  "figure.text.part-is-referenced": "无法删除 '{part}':有其他部件固定在它上面或跟随它的尺寸。请先解除该连接。",
47
53
  "figure.text.part-name-invalid": "'{name}' 不能作为部件名称。请以字母开头,只使用字母、数字、- 和 _。",
@@ -559,5 +565,19 @@
559
565
  "figure.button.keep-changed-appearance": "以调整后的模型宽度发布",
560
566
  "figure.button.restore-released-base": "恢复为之前的模型宽度",
561
567
  "figure.text.appearance-choice-explained": "恢复会把 X 和 Z 还原为上次发布的值,并保留 Y 及其他所有编辑。以调整后的宽度发布则保留当前模型轮廓。",
562
- "figure.text.choose-appearance-change": "请选择如何处理调整后的模型宽度"
568
+ "figure.text.choose-appearance-change": "请选择如何处理调整后的模型宽度",
569
+ "figure.label.places": "位置",
570
+ "figure.text.places-need-a-box": "位置设在方盒形部件的面上。",
571
+ "figure.label.place-grip": "夹持位置",
572
+ "figure.label.place-seat": "放置位置",
573
+ "figure.label.place-holds": "最多 {count} 个",
574
+ "figure.button.remove-place": "删除位置",
575
+ "figure.text.place-explained": "决定在看板上物品放在或夹在这个部件的哪个面上。部件移动时,物品也随之移动。",
576
+ "figure.text.place-needs-holding": "这个图形没有声明可以容纳物品,所以即使设了位置,看板也不会把物品交给它。",
577
+ "figure.button.declare-holding": "设为可容纳物品的图形",
578
+ "figure.label.place-name": "名称",
579
+ "figure.label.place-accepts": "接收类型",
580
+ "figure.label.place-capacity": "最多数量",
581
+ "figure.text.place-accepts-needed": "至少填写一个接收类型,用逗号分隔。",
582
+ "figure.button.add-place": "添加位置"
563
583
  }
@@ -1,70 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- */
4
-
5
- /**
6
- * 막대 옆에 서는 **각도 눈**. 지금 각이 범위의 어디인지를 한 눈에 보인다.
7
- *
8
- * ## 왜 3D 로는 모자랐나
9
- *
10
- * 관절이 돌아도 화면이 그대로인 경우가 있다 — 제 축에서 대칭인 부품이 그렇다. 그래서 관절이
11
- * 모는 부품에 바늘을 달아 미리보기에서 함께 돌게 했는데(`joint-gizmo.ts` 의 `jointNeedles`),
12
- * **미리보기에서는 그 바늘이 4 × 2 픽셀이다**(잰 값: 부품 100mm · 바늘 60 × 12mm · 여덟 대를
13
- * 한 화면에 세운 상태). 미리보기는 크기 반응을 보려고 여덟 대를 나란히 놓는 자리라 한 대가
14
- * 20 픽셀쯤이고, 그 위의 어떤 표시도 몇 픽셀을 넘지 못한다.
15
- *
16
- * 각을 읽는 일은 3D 의 배율에서 떼어 놓는다. 눈은 막대 옆 24 픽셀 자리에 서고, 도형이 아무리
17
- * 작게 서 있어도 같은 크기로 읽힌다.
18
- */
19
-
20
- export interface DialShape {
21
- /** 가동 범위를 채운 부채꼴. SVG path 의 `d`. */
22
- sector: string
23
- /** 지금 값이 가리키는 끝점. */
24
- needle: { x: number; y: number }
25
- centre: { x: number; y: number }
26
- radius: number
27
- }
28
-
29
- /** 0 도가 위를 가리키고, 값이 커지면 시계 방향으로 돈다 — 화면의 각과 같은 방향이다. */
30
- function at(centre: { x: number; y: number }, radius: number, degrees: number) {
31
- const rad = (degrees * Math.PI) / 180
32
- return {
33
- x: +(centre.x + radius * Math.sin(rad)).toFixed(2),
34
- y: +(centre.y - radius * Math.cos(rad)).toFixed(2)
35
- }
36
- }
37
-
38
- /** 한 바퀴에 가까우면 부채꼴 대신 온전한 원이다. */
39
- const FULL = 359.9
40
-
41
- /**
42
- * 눈의 모양. 값이 범위를 벗어나면 범위 끝에 세운다 — 밖을 가리키는 바늘은 없는 값을 말한다.
43
- */
44
- export function dialShape(min: number, max: number, value: number, radius = 9): DialShape {
45
- const centre = { x: radius + 1, y: radius + 1 }
46
- const span = Math.abs(max - min)
47
- const held = Math.min(Math.max(value, Math.min(min, max)), Math.max(min, max))
48
-
49
- if (span >= FULL) {
50
- const top = at(centre, radius, 0)
51
- const bottom = at(centre, radius, 180)
52
- return {
53
- sector: `M ${top.x} ${top.y} A ${radius} ${radius} 0 1 1 ${bottom.x} ${bottom.y} A ${radius} ${radius} 0 1 1 ${top.x} ${top.y} Z`,
54
- needle: at(centre, radius, held),
55
- centre,
56
- radius
57
- }
58
- }
59
-
60
- const from = at(centre, radius, min)
61
- const to = at(centre, radius, max)
62
- const large = span > 180 ? 1 : 0
63
-
64
- return {
65
- sector: `M ${centre.x} ${centre.y} L ${from.x} ${from.y} A ${radius} ${radius} 0 ${large} 1 ${to.x} ${to.y} Z`,
66
- needle: at(centre, radius, held),
67
- centre,
68
- radius
69
- }
70
- }
@@ -1,175 +0,0 @@
1
- /*
2
- * Copyright © HatioLab Inc. All rights reserved.
3
- */
4
-
5
- import { rotatedExtentOf } from '@hatiolab/figure-model'
6
-
7
- import type { FigureDraft, PartModel } from './figure-source.js'
8
-
9
- /**
10
- * 기준 상자를 고친다 — **부품은 제자리에 둔 채.**
11
- *
12
- * ## 왜 화면에 있어야 하나
13
- *
14
- * 기준 상자는 도면에 놓일 때의 배율을 정하는 수다(ADR-0044 ①). 부품이 그 상자를 넘으면 발행이
15
- * 막히고, 고치는 길은 「상자 숫자 하나를 키우는 것」인데 **화면에 그 칸이 없었다.** 저작자는
16
- * 넘쳤다는 말만 듣고 고칠 자리를 못 찾았다.
17
- *
18
- * ## 상자를 키우면 부품이 움직인다 — 그것을 되돌린다
19
- *
20
- * 저작면의 부품 자리는 판의 왼쪽 위에서 잰 값이고, 저장 형식의 자리는 **상자의 한가운데**에서 잰
21
- * 값이다(`toFigureSource` 가 절반을 뺀다). 그래서 상자만 키우면 한가운데가 옮겨 가고 부품이 전부
22
- * 반대로 밀린다. 여기서 늘어난 절반만큼 부품을 함께 옮겨, 저장되는 자리가 한 값도 안 바뀌게 한다.
23
- *
24
- * ## 「부품에 맞추기」는 한가운데를 지킨다
25
- *
26
- * 부품을 감싸는 가장 작은 상자를 만들 때, 부품 쪽을 **옮기지 않는다.** 한가운데에서 가장 먼
27
- * 부품까지의 거리를 양쪽으로 잡는다. 부품이 한쪽으로 치우쳐 있으면 반대쪽에 여유가 남는데,
28
- * 그것이 사실이다 — 치우친 것을 가운데로 끌어오면 저작자가 놓은 자리가 소리 없이 달라지고,
29
- * 발행된 도형에서는 문(port)의 자리가 함께 움직인다.
30
- *
31
- * 높이는 밑면이 바닥이라 한쪽만 늘린다. 바닥 아래로 내려간 부품이 있으면 그 부품은 상자 밖에
32
- * 남는다 — 그것을 담으려면 부품을 올려야 하고, 그것은 저작자가 정할 일이다. 발행 관문이 이미
33
- * `part-outside-base` 로 말한다.
34
- *
35
- * ## 돌아간 부품은 돌아간 부피로 잰다
36
- *
37
- * 45 도 돌린 판은 제 `size` 보다 넓게 자리를 차지한다. 발행 관문은 그것을 `rotatedExtentOf` 로
38
- * 재는데 여기서는 `width`·`height` 를 그대로 썼다. 그래서 **회전한 부품이 있는 도형은 「부품에
39
- * 맞추기」를 눌러도 발행이 막힌 채로 남았다** — 표본에서 CONVEYOR(부품 17 중 4 가 회전)와
40
- * ROLL_CRADLE(20 중 13)이 그랬다(2026-09-19 확인). 같은 함수로 재서 둘이 어긋나지 않게 한다.
41
- */
42
-
43
- export interface BaseSize {
44
- /** 저작면의 가로 — 형식의 `base.x`. */
45
- width: number
46
- /** 저작면의 세로 — 형식의 `base.z`. */
47
- height: number
48
- /** 높이 — 형식의 `base.y`. */
49
- depth: number
50
- }
51
-
52
- /** 상자는 밀리미터 하나보다 작아질 수 없다. 0 이 되면 배율이 0 으로 나뉜다. */
53
- const LEAST = 1
54
-
55
- const round = (value: number) => Math.round(value)
56
-
57
- export const baseOf = (draft: FigureDraft): BaseSize => ({
58
- width: draft.width,
59
- height: draft.height,
60
- depth: draft.depth
61
- })
62
-
63
- const DEG = 180 / Math.PI
64
-
65
- /**
66
- * 이 부품이 차지하는 부피 — **형식의 축으로**.
67
- *
68
- * 저작면과 형식의 축 이름이 엇갈린다(`figure-source.ts` 의 표): 저작면의 `depth` 가 형식의 y 이고
69
- * `height` 가 형식의 z 다. 회전 이름도 엇갈린다(`rotationY` → 형식의 z). 그 표를 여기서 다시
70
- * 적지 않고 같은 모양으로 옮겨, `rotatedExtentOf` 가 관문에서와 같은 답을 내게 한다.
71
- */
72
- function extentOf(part: PartModel): { x: number; y: number; z: number } {
73
- return rotatedExtentOf({
74
- transform: {
75
- position: { x: 0, y: 0, z: 0 },
76
- size: { x: part.width, y: part.depth, z: part.height },
77
- rotation: {
78
- x: part.rotationX ? part.rotationX * DEG : 0,
79
- y: part.rotation ? -part.rotation * DEG : 0,
80
- z: part.rotationY ? part.rotationY * DEG : 0
81
- }
82
- }
83
- } as never)
84
- }
85
-
86
- /**
87
- * 부품 전부를 **바닥에 앉힌다** — 가장 낮은 것이 상자 밑면에 닿도록 전부를 같은 값만큼 옮긴다.
88
- *
89
- * ## 왜 전부를 옮기나
90
- *
91
- * 관문이 막는 것은 「가장 낮은 부품이 밑면에 안 닿는다」다(`parts-off-placement-face`). 그 부품
92
- * 하나만 내리면 관문은 통과하지만 도형이 달라진다 — 프레임에 붙어 있던 발이 떨어진다. 부품 사이의
93
- * 자리는 저작자가 정한 것이므로 그것을 지키고 전체를 옮긴다.
94
- *
95
- * ## 위로도 옮긴다
96
- *
97
- * 바닥 **아래로** 내려간 부품이 있으면 올린다. 그때는 위쪽이 상자를 넘을 수 있으므로 저작자가
98
- * 「부품에 맞추기」를 이어서 누르게 된다 — 두 조치가 각자 한 가지만 한다.
99
- *
100
- * 앉힐 것이 없으면 **받은 것을 그대로 돌려준다** — 고친 것이 없는데 「저장 안 됨」이 붙지 않게.
101
- */
102
- export function partsSettledOnFloor(parts: readonly PartModel[]): readonly PartModel[] {
103
- if (parts.length === 0) return parts
104
-
105
- let lowest = Infinity
106
- for (const part of parts) {
107
- const extent = extentOf(part)
108
- lowest = Math.min(lowest, part.zPos + part.depth / 2 - extent.y / 2)
109
- }
110
-
111
- const shift = round(lowest)
112
- if (shift === 0) return parts
113
-
114
- return parts.map(part => ({ ...part, zPos: round(part.zPos - shift) }))
115
- }
116
-
117
- /** 부품 전부를 담는 가장 작은 상자. 부품이 없으면 잴 것이 없다. */
118
- export function baseFittingParts(draft: FigureDraft, parts: readonly PartModel[]): BaseSize | undefined {
119
- if (parts.length === 0) return undefined
120
-
121
- const middle = { x: draft.width / 2, y: draft.height / 2 }
122
- let half = { x: 0, y: 0 }
123
- let tallest = 0
124
-
125
- for (const part of parts) {
126
- /* 돌아간 부피. 관문이 재는 것과 같은 함수로 잰다 — 다르게 재면 눌러도 막힌 채로 남는다. */
127
- const extent = extentOf(part)
128
- const centre = {
129
- x: part.left + part.width / 2,
130
- y: part.top + part.height / 2,
131
- z: part.zPos + part.depth / 2
132
- }
133
-
134
- half = {
135
- x: Math.max(half.x, Math.abs(centre.x - extent.x / 2 - middle.x), Math.abs(centre.x + extent.x / 2 - middle.x)),
136
- y: Math.max(half.y, Math.abs(centre.y - extent.z / 2 - middle.y), Math.abs(centre.y + extent.z / 2 - middle.y))
137
- }
138
- tallest = Math.max(tallest, centre.z + extent.y / 2)
139
- }
140
-
141
- return {
142
- width: Math.max(LEAST, round(half.x * 2)),
143
- height: Math.max(LEAST, round(half.y * 2)),
144
- depth: Math.max(LEAST, round(tallest))
145
- }
146
- }
147
-
148
- /**
149
- * 상자를 이 크기로. 부품은 저장되는 자리가 그대로이도록 함께 옮긴다.
150
- *
151
- * 달라질 것이 없으면 **받은 것을 그대로 돌려준다** — 고친 것이 없는데 「저장 안 됨」이 붙지 않게.
152
- */
153
- export function resizeBase(
154
- draft: FigureDraft,
155
- parts: readonly PartModel[],
156
- next: BaseSize
157
- ): { draft: FigureDraft; parts: readonly PartModel[] } {
158
- const size = {
159
- width: Math.max(LEAST, round(next.width)),
160
- height: Math.max(LEAST, round(next.height)),
161
- depth: Math.max(LEAST, round(next.depth))
162
- }
163
-
164
- if (size.width === draft.width && size.height === draft.height && size.depth === draft.depth) {
165
- return { draft, parts }
166
- }
167
-
168
- const shift = { x: (size.width - draft.width) / 2, y: (size.height - draft.height) / 2 }
169
- const moved =
170
- shift.x === 0 && shift.y === 0
171
- ? parts
172
- : parts.map(part => ({ ...part, left: part.left + shift.x, top: part.top + shift.y }))
173
-
174
- return { draft: { ...draft, ...size }, parts: moved }
175
- }