diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index 8207ef59e..54ddae65e 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -295,6 +295,16 @@ command-copy = .mode = COPY أدخل خيار وضع النسخ [Single/Multiple] : common = + .assoc-array-array-path = مصفوفة (مسار) + .assoc-array-array-polar = مصفوفة (قطبية) + .assoc-array-array-rectangular = مصفوفة (مستطيلة) + .assoc-array-item-spacing = تباعد العناصر + .assoc-array-fill-angle = زاوية التعبئة + .assoc-array-items = العناصر + .assoc-array-level-spacing = تباعد المستويات + .assoc-array-levels = المستويات + .assoc-array-row-spacing = تباعد الصفوف + .assoc-array-column-spacing = تباعد الأعمدة .fbxexport-exported-to = FBXEXPORT: تم التصدير إلى "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: لا توجد بيانات شبكة ثلاثية الأبعاد في هذا الرسم. .fbxexport-error = FBXEXPORT: ‏__ocs_fmt_0__ diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index 40ae5fd0c..caac7af4f 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -282,6 +282,16 @@ command-copy = .displacement = COPY Задайте преместване: .mode = COPY Въведете режим на копиране [Single/Multiple] : common = + .assoc-array-array-path = Масив (по път) + .assoc-array-array-polar = Масив (полярен) + .assoc-array-array-rectangular = Масив (правоъгълен) + .assoc-array-item-spacing = Разстояние между елементите + .assoc-array-fill-angle = Ъгъл на запълване + .assoc-array-items = Елементи + .assoc-array-level-spacing = Разстояние между нивата + .assoc-array-levels = Нива + .assoc-array-row-spacing = Разстояние между редовете + .assoc-array-column-spacing = Разстояние между колоните .fbxexport-exported-to = FBXEXPORT: експортирано в "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: няма 3D данни за мрежа в този чертеж. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index 20bd79f59..4d14ecb17 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -282,6 +282,16 @@ command-copy = .mode = COPY Zadejte režim kopírování [Single/Multiple] : common = + .assoc-array-array-path = Pole (podél cesty) + .assoc-array-array-polar = Pole (kruhové) + .assoc-array-array-rectangular = Pole (obdélníkové) + .assoc-array-item-spacing = Rozteč položek + .assoc-array-fill-angle = Úhel vyplnění + .assoc-array-items = Položky + .assoc-array-level-spacing = Rozteč úrovní + .assoc-array-levels = Úrovně + .assoc-array-row-spacing = Rozteč řádků + .assoc-array-column-spacing = Rozteč sloupců .fbxexport-exported-to = FBXEXPORT: exportováno do "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: v tomto výkresu nejsou žádná data 3D sítě. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index 0d2dcc9dc..f7f626bcb 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -283,6 +283,16 @@ command-copy = .mode = COPY Kopiermodus eingeben [Single/Multiple] : common = + .assoc-array-array-path = Reihe (Pfad) + .assoc-array-array-polar = Reihe (polar) + .assoc-array-array-rectangular = Reihe (rechteckig) + .assoc-array-item-spacing = Elementabstand + .assoc-array-fill-angle = Füllwinkel + .assoc-array-items = Elemente + .assoc-array-level-spacing = Ebenenabstand + .assoc-array-levels = Ebenen + .assoc-array-row-spacing = Zeilenabstand + .assoc-array-column-spacing = Spaltenabstand .fbxexport-exported-to = FBXEXPORT: exportiert nach "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: keine 3D-Mesh-Daten in dieser Zeichnung. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index 51b4ac6a6..665c5f931 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -282,6 +282,16 @@ command-copy = .mode = COPY Επιλέξτε λειτουργία αντιγραφής [Single/Multiple] : common = + .assoc-array-array-path = Πίνακας (διαδρομή) + .assoc-array-array-polar = Πίνακας (πολικός) + .assoc-array-array-rectangular = Πίνακας (ορθογώνιος) + .assoc-array-item-spacing = Απόσταση στοιχείων + .assoc-array-fill-angle = Γωνία πλήρωσης + .assoc-array-items = Στοιχεία + .assoc-array-level-spacing = Απόσταση επιπέδων + .assoc-array-levels = Επίπεδα + .assoc-array-row-spacing = Απόσταση γραμμών + .assoc-array-column-spacing = Απόσταση στηλών .fbxexport-exported-to = FBXEXPORT: εξήχθη στο "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: δεν υπάρχουν δεδομένα πλέγματος 3D σε αυτό το σχέδιο. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index 3acca6474..1a7e856c3 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -282,6 +282,16 @@ command-copy = .mode = COPY Enter a copy mode option [Single/Multiple] : common = + .assoc-array-array-path = Array (Path) + .assoc-array-array-polar = Array (Polar) + .assoc-array-array-rectangular = Array (Rectangular) + .assoc-array-item-spacing = Item spacing + .assoc-array-fill-angle = Fill angle + .assoc-array-items = Items + .assoc-array-level-spacing = Level spacing + .assoc-array-levels = Levels + .assoc-array-row-spacing = Row spacing + .assoc-array-column-spacing = Column spacing .fbxexport-exported-to = FBXEXPORT: exported to "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: no 3D mesh data in this drawing. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index d65fb5594..ef384b506 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -283,6 +283,16 @@ command-copy = .mode = COPY Indique modo de copia [Single/Multiple] : common = + .assoc-array-array-path = Matriz (trayectoria) + .assoc-array-array-polar = Matriz (polar) + .assoc-array-array-rectangular = Matriz (rectangular) + .assoc-array-item-spacing = Espaciado de elementos + .assoc-array-fill-angle = Ángulo de relleno + .assoc-array-items = Elementos + .assoc-array-level-spacing = Espaciado de niveles + .assoc-array-levels = Niveles + .assoc-array-row-spacing = Espaciado de filas + .assoc-array-column-spacing = Espaciado de columnas .fbxexport-exported-to = FBXEXPORT: exportado a «__ocs_fmt_0__» .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: no hay datos de malla 3D en este dibujo. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index 0ddf32791..a2780d625 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -282,6 +282,16 @@ command-copy = .mode = COPY Valitse kopiointitila [Single/Multiple] : common = + .assoc-array-array-path = Taulukko (polku) + .assoc-array-array-polar = Taulukko (polaarinen) + .assoc-array-array-rectangular = Taulukko (suorakulmainen) + .assoc-array-item-spacing = Kohdeväli + .assoc-array-fill-angle = Täyttökulma + .assoc-array-items = Kohteet + .assoc-array-level-spacing = Tasoväli + .assoc-array-levels = Tasot + .assoc-array-row-spacing = Riviväli + .assoc-array-column-spacing = Sarakeväli .fbxexport-exported-to = FBXEXPORT: viety tiedostoon "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: tässä piirustuksessa ei ole 3D-verkkotietoja. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index b2a305e99..f0a89f5fc 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -283,6 +283,16 @@ command-copy = .mode = COPY Entrez le mode de copie [Single/Multiple] : common = + .assoc-array-array-path = Réseau (trajectoire) + .assoc-array-array-polar = Réseau (polaire) + .assoc-array-array-rectangular = Réseau (rectangulaire) + .assoc-array-item-spacing = Espacement des éléments + .assoc-array-fill-angle = Angle de remplissage + .assoc-array-items = Éléments + .assoc-array-level-spacing = Espacement des niveaux + .assoc-array-levels = Niveaux + .assoc-array-row-spacing = Espacement des rangées + .assoc-array-column-spacing = Espacement des colonnes .fbxexport-exported-to = FBXEXPORT: exporté vers "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: aucune donnée de maillage 3D dans ce dessin. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index c4419002b..6f8c8cff4 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -271,6 +271,16 @@ command-copy = .mode = COPY कॉपी मोड विकल्प दर्ज करें [Single/Multiple] : common = + .assoc-array-array-path = ऐरे (पथ) + .assoc-array-array-polar = ऐरे (ध्रुवीय) + .assoc-array-array-rectangular = ऐरे (आयताकार) + .assoc-array-item-spacing = आइटम अंतराल + .assoc-array-fill-angle = भरण कोण + .assoc-array-items = आइटम + .assoc-array-level-spacing = स्तर अंतराल + .assoc-array-levels = स्तर + .assoc-array-row-spacing = पंक्ति अंतराल + .assoc-array-column-spacing = कॉलम अंतराल .fbxexport-exported-to = FBXEXPORT: "__ocs_fmt_0__" में निर्यात किया गया .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: इस ड्रॉइंग में कोई 3D मेश डेटा नहीं है। .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index 22e9b2090..d9e0e6191 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -281,6 +281,16 @@ command-copy = .mode = COPY Adja meg a másolási módot [Single/Multiple] : common = + .assoc-array-array-path = Tömb (útvonal) + .assoc-array-array-polar = Tömb (poláris) + .assoc-array-array-rectangular = Tömb (téglalap) + .assoc-array-item-spacing = Elemtávolság + .assoc-array-fill-angle = Kitöltési szög + .assoc-array-items = Elemek + .assoc-array-level-spacing = Szinttávolság + .assoc-array-levels = Szintek + .assoc-array-row-spacing = Sortávolság + .assoc-array-column-spacing = Oszloptávolság .fbxexport-exported-to = FBXEXPORT: exportálva a következőbe: "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: a rajz nem tartalmaz 3D hálóadatot. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index 05821a5c6..084c7be63 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -282,6 +282,16 @@ command-copy = .mode = COPY Specificare modalità di copia [Single/Multiple] : common = + .assoc-array-array-path = Serie (percorso) + .assoc-array-array-polar = Serie (polare) + .assoc-array-array-rectangular = Serie (rettangolare) + .assoc-array-item-spacing = Spaziatura elementi + .assoc-array-fill-angle = Angolo di riempimento + .assoc-array-items = Elementi + .assoc-array-level-spacing = Spaziatura livelli + .assoc-array-levels = Livelli + .assoc-array-row-spacing = Spaziatura righe + .assoc-array-column-spacing = Spaziatura colonne .fbxexport-exported-to = FBXEXPORT: esportato in "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: nessun dato mesh 3D in questo disegno. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index 8400e323d..c8e6e5786 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -273,6 +273,16 @@ command-copy = .mode = COPY コピーモードを入力 [Single/Multiple] : common = + .assoc-array-array-path = 配列複写 (パス) + .assoc-array-array-polar = 配列複写 (円形状) + .assoc-array-array-rectangular = 配列複写 (矩形状) + .assoc-array-item-spacing = 項目の間隔 + .assoc-array-fill-angle = 充填角度 + .assoc-array-items = 項目 + .assoc-array-level-spacing = レベルの間隔 + .assoc-array-levels = レベル + .assoc-array-row-spacing = 行の間隔 + .assoc-array-column-spacing = 列の間隔 .fbxexport-exported-to = FBXEXPORT: "__ocs_fmt_0__" に書き出しました .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: この図面に 3D メッシュデータがありません。 .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index 20f1146d9..bc8c8e056 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -282,6 +282,16 @@ command-copy = .mode = COPY 복사 모드 옵션 입력 [Single/Multiple] : common = + .assoc-array-array-path = 배열 (경로) + .assoc-array-array-polar = 배열 (원형) + .assoc-array-array-rectangular = 배열 (직사각형) + .assoc-array-item-spacing = 항목 간격 + .assoc-array-fill-angle = 채우기 각도 + .assoc-array-items = 항목 + .assoc-array-level-spacing = 레벨 간격 + .assoc-array-levels = 레벨 + .assoc-array-row-spacing = 행 간격 + .assoc-array-column-spacing = 열 간격 .fbxexport-exported-to = FBXEXPORT: "__ocs_fmt_0__"로 내보냈습니다. .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: 이 도면에는 3D 메쉬 데이터가 없습니다. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/lo-LA/opencadstudio.ftl b/locales/lo-LA/opencadstudio.ftl index dce7b0f10..dc08d761c 100644 --- a/locales/lo-LA/opencadstudio.ftl +++ b/locales/lo-LA/opencadstudio.ftl @@ -282,6 +282,16 @@ command-copy = .mode = COPY ປ້ອນຕົວເລືອກໂໝດການຄັດລອກ [Single/Multiple] : common = + .assoc-array-array-path = ອາເຣ (ເສັ້ນທາງ) + .assoc-array-array-polar = ອາເຣ (ວົງມົນ) + .assoc-array-array-rectangular = ອາເຣ (ສີ່ຫຼ່ຽມ) + .assoc-array-item-spacing = ໄລຍະຫ່າງລາຍການ + .assoc-array-fill-angle = ມຸມເຕີມ + .assoc-array-items = ລາຍການ + .assoc-array-level-spacing = ໄລຍະຫ່າງລະດັບ + .assoc-array-levels = ລະດັບ + .assoc-array-row-spacing = ໄລຍະຫ່າງແຖວ + .assoc-array-column-spacing = ໄລຍະຫ່າງຖັນ .fbxexport-exported-to = FBXEXPORT: ສົ່ງອອກໄປທີ່ "__ocs_fmt_0__" ແລ້ວ .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: ບໍ່ມີຂໍ້ມູນເມຊ 3D ໃນຮູບແຕ້ມນີ້. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index 4e71bcba6..93ef29985 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -283,6 +283,16 @@ command-copy = .mode = COPY Geef kopieermodus op [Single/Multiple] : common = + .assoc-array-array-path = Reeks (pad) + .assoc-array-array-polar = Reeks (polair) + .assoc-array-array-rectangular = Reeks (rechthoekig) + .assoc-array-item-spacing = Itemafstand + .assoc-array-fill-angle = Vulhoek + .assoc-array-items = Items + .assoc-array-level-spacing = Niveau-afstand + .assoc-array-levels = Niveaus + .assoc-array-row-spacing = Rijafstand + .assoc-array-column-spacing = Kolomafstand .fbxexport-exported-to = FBXEXPORT: geëxporteerd naar "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: geen 3D-maasgegevens in deze tekening. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index ca5701316..37ceb77c7 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -282,6 +282,16 @@ command-copy = .mode = COPY Podaj tryb kopiowania [Single/Multiple] : common = + .assoc-array-array-path = Szyk (ścieżka) + .assoc-array-array-polar = Szyk (biegunowy) + .assoc-array-array-rectangular = Szyk (prostokątny) + .assoc-array-item-spacing = Odstęp elementów + .assoc-array-fill-angle = Kąt wypełnienia + .assoc-array-items = Elementy + .assoc-array-level-spacing = Odstęp poziomów + .assoc-array-levels = Poziomy + .assoc-array-row-spacing = Odstęp wierszy + .assoc-array-column-spacing = Odstęp kolumn .fbxexport-exported-to = FBXEXPORT: wyeksportowano do „__ocs_fmt_0__” .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: brak danych siatki 3D na tym rysunku. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index 073ee7505..8ff75756a 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -283,6 +283,16 @@ command-copy = .mode = COPY Informe o modo de cópia [Single/Multiple] : common = + .assoc-array-array-path = Matriz (caminho) + .assoc-array-array-polar = Matriz (polar) + .assoc-array-array-rectangular = Matriz (retangular) + .assoc-array-item-spacing = Espaçamento dos itens + .assoc-array-fill-angle = Ângulo de preenchimento + .assoc-array-items = Itens + .assoc-array-level-spacing = Espaçamento dos níveis + .assoc-array-levels = Níveis + .assoc-array-row-spacing = Espaçamento das linhas + .assoc-array-column-spacing = Espaçamento das colunas .fbxexport-exported-to = FBXEXPORT: exportado para “__ocs_fmt_0__” .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: não há dados de malha 3D neste desenho. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index 273d70a61..2deb1f83f 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -286,6 +286,16 @@ command-copy = .mode = COPY Задайте режим копирования [Single/Multiple] : common = + .assoc-array-array-path = Массив (по траектории) + .assoc-array-array-polar = Массив (круговой) + .assoc-array-array-rectangular = Массив (прямоугольный) + .assoc-array-item-spacing = Расстояние между элементами + .assoc-array-fill-angle = Угол заполнения + .assoc-array-items = Элементы + .assoc-array-level-spacing = Расстояние между уровнями + .assoc-array-levels = Уровни + .assoc-array-row-spacing = Расстояние между рядами + .assoc-array-column-spacing = Расстояние между столбцами .fbxexport-exported-to = FBXEXPORT: экспортируется в "__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: в этом чертеже нет данных 3D-сети. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index c1a847034..103792d3a 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -268,6 +268,16 @@ command-copy = .mode = COPY Kopyalama modu seçin [Single/Multiple] : common = + .assoc-array-array-path = Dizi (Yol) + .assoc-array-array-polar = Dizi (Kutupsal) + .assoc-array-array-rectangular = Dizi (Dikdörtgen) + .assoc-array-item-spacing = Öğe aralığı + .assoc-array-fill-angle = Doldurma açısı + .assoc-array-items = Öğeler + .assoc-array-level-spacing = Seviye aralığı + .assoc-array-levels = Seviyeler + .assoc-array-row-spacing = Satır aralığı + .assoc-array-column-spacing = Sütun aralığı .fbxexport-exported-to = FBXEXPORT: "__ocs_fmt_0__" konumuna dışa aktarıldı .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT: Bu çizimde 3B örgü verisi yok. .fbxexport-error = FBXEXPORT: __ocs_fmt_0__ diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index 3fc175968..14d64345a 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -270,6 +270,16 @@ command-copy = .mode = COPY 输入复制模式选项 [Single/Multiple] : common = + .assoc-array-array-path = 阵列 (路径) + .assoc-array-array-polar = 阵列 (环形) + .assoc-array-array-rectangular = 阵列 (矩形) + .assoc-array-item-spacing = 项目间距 + .assoc-array-fill-angle = 填充角度 + .assoc-array-items = 项目 + .assoc-array-level-spacing = 层间距 + .assoc-array-levels = 层数 + .assoc-array-row-spacing = 行间距 + .assoc-array-column-spacing = 列间距 .fbxexport-exported-to = FBXEXPORT:导出为"__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT:此绘图中没有3D网格数据。 .fbxexport-error = FBXEXPORT:__ocs_fmt_0__ 时间轴: diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index 3e569deed..be38f6cbc 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -282,6 +282,16 @@ command-copy = .mode = COPY 輸入複製模式選項 [Single/Multiple] : common = + .assoc-array-array-path = 陣列 (路徑) + .assoc-array-array-polar = 陣列 (環形) + .assoc-array-array-rectangular = 陣列 (矩形) + .assoc-array-item-spacing = 項目間距 + .assoc-array-fill-angle = 填滿角度 + .assoc-array-items = 項目 + .assoc-array-level-spacing = 層間距 + .assoc-array-levels = 層數 + .assoc-array-row-spacing = 列間距 + .assoc-array-column-spacing = 欄間距 .fbxexport-exported-to = FBXEXPORT:匯出為"__ocs_fmt_0__" .fbxexport-no-3d-mesh-data-in-this-drawing = FBXEXPORT:此繪圖中沒有3D網格資料。 .fbxexport-error = FBXEXPORT:__ocs_fmt_0__ 時間軸: diff --git a/src/app/properties.rs b/src/app/properties.rs index 80992ee57..45450df84 100644 --- a/src/app/properties.rs +++ b/src/app/properties.rs @@ -924,6 +924,10 @@ impl OpenCADStudio { crate::io::xref::layer_overrides(doc, &br.name, &br.xref_path, &base_dir); xref_rows(&mut sections, ins, &br.xref_path, factor, overrides); } + // An associative array's counts and spacings. + if let Some(array) = crate::scene::assoc_array::array_of_insert(doc, handle) { + sections.push(crate::scene::assoc_array::property_section(doc, &array)); + } } // Underlay: name, page, path and size from the definition. codec::EntityType::Underlay(ul) => { diff --git a/src/app/update/command.rs b/src/app/update/command.rs index a7a95e16a..b0bdad065 100644 --- a/src/app/update/command.rs +++ b/src/app/update/command.rs @@ -3748,6 +3748,40 @@ impl OpenCADStudio { Task::none() } + /// An associative array row: the typed value changes the array's + /// parameter and its items are placed again, in one undo step. + fn on_assoc_array_field_commit(&mut self, i: usize, field: &'static str, handles: &[Handle]) { + let Some(text) = self.tabs[i] + .properties + .edit_buf + .remove(&crate::ui::properties::FieldKey::Geom(field)) + else { + return; + }; + let arrays: Vec<_> = handles + .iter() + .filter_map(|handle| { + crate::scene::assoc_array::array_of_insert(&self.tabs[i].scene.document, *handle) + }) + .collect(); + if arrays.is_empty() { + return; + } + self.push_undo_snapshot(i, "ARRAYEDIT"); + for array in &arrays { + if let Err(error) = crate::scene::assoc_array::apply_field( + &mut self.tabs[i].scene, + array, + field, + &crate::app::expr_eval::eval_to_string(&text), + ) { + self.command_line.push_error(&format!("ARRAYEDIT: {error}")); + } + } + self.tabs[i].dirty = true; + self.refresh_properties(); + } + pub(super) fn on_prop_geom_commit(&mut self, field: &'static str) -> Task { use crate::ui::window::named_parameters::ParamField; // A dynamic dimension's Name/Expression rows edit its parameter. @@ -3765,6 +3799,10 @@ impl OpenCADStudio { let i = self.active_tab; self.tabs[i].properties.active_field = None; let handles = self.property_target_handles(i); + if field.starts_with("assoc_array_") { + self.on_assoc_array_field_commit(i, field, &handles); + return Task::none(); + } if !handles.is_empty() { let driven_reference = match field { "start_x" | "start_y" | "start_z" => Some(Some(0)), diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index 3a3c07355..c73cbb067 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -3702,6 +3702,16 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static "Width factor" => Some(("common", "width-factor-sentence-case")), "Width: %{value}" => Some(("ui", "width-value")), "Window" => Some(("common", "window")), + "Column spacing" => Some(("common", "assoc-array-column-spacing")), + "Row spacing" => Some(("common", "assoc-array-row-spacing")), + "Levels" => Some(("common", "assoc-array-levels")), + "Level spacing" => Some(("common", "assoc-array-level-spacing")), + "Items" => Some(("common", "assoc-array-items")), + "Fill angle" => Some(("common", "assoc-array-fill-angle")), + "Item spacing" => Some(("common", "assoc-array-item-spacing")), + "Array (Rectangular)" => Some(("common", "assoc-array-array-rectangular")), + "Array (Polar)" => Some(("common", "assoc-array-array-polar")), + "Array (Path)" => Some(("common", "assoc-array-array-path")), "Window Elements" => Some(("common", "options-window-elements")), "Show the menu bar (MENUBAR)" => Some(("common", "options-show-menu-bar")), "Show the ribbon (RIBBON / RIBBONCLOSE)" => Some(("common", "options-show-ribbon")), diff --git a/src/scene/assoc_array.rs b/src/scene/assoc_array.rs new file mode 100644 index 000000000..133b5b51d --- /dev/null +++ b/src/scene/assoc_array.rs @@ -0,0 +1,558 @@ +//! Associative arrays as the drawing stores them: an AcDbAssocAction whose +//! body is an AcDbAssocArrayActionBody, with dependencies on the array INSERT +//! (read + write), the anonymous block holding the item INSERTs (write) and the +//! anonymous block holding the source objects (read). The action's value +//! parameters (Items, ItemSpacing, Rows, …) define where the items go. + +use codec::objects::{ + AssocAction, AssocArrayActionBody, AssocDependency, AssocEvalValue, AssocValueParam, + AssociativeData, ObjectType, +}; +use codec::{CadDocument, Handle}; +use glam::{DMat4, DVec3}; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ArrayKind { + Rectangular, + Polar, + Path, +} + +/// One associative array, resolved from its array INSERT. +#[derive(Clone, Debug)] +pub struct AssocArray { + pub insert: Handle, + pub action: Handle, + pub body: Handle, + /// Block record holding the item INSERTs. + pub array_block: Handle, + /// Block record holding the source objects. + pub source_block: Handle, + pub kind: ArrayKind, +} + +fn dependency(document: &CadDocument, handle: Handle) -> Option<&AssocDependency> { + match document.objects.get(&handle)? { + ObjectType::Associative(object) => match &object.data { + AssociativeData::Dependency(dependency) => Some(dependency), + AssociativeData::GeomDependency(geom) => Some(&geom.dependency), + AssociativeData::ValueDependency(value) => Some(&value.dependency), + _ => None, + }, + _ => None, + } +} + +pub fn action(document: &CadDocument, handle: Handle) -> Option<&AssocAction> { + match document.objects.get(&handle)? { + ObjectType::Associative(object) => match &object.data { + AssociativeData::Action(action) => Some(action), + _ => None, + }, + _ => None, + } +} + +pub fn body(document: &CadDocument, handle: Handle) -> Option<&AssocArrayActionBody> { + match document.objects.get(&handle)? { + ObjectType::Associative(object) => match &object.data { + AssociativeData::ArrayActionBody(body) => Some(body), + AssociativeData::ArrayModifyActionBody(modify) => Some(&modify.body), + _ => None, + }, + _ => None, + } +} + +/// The associative array whose array INSERT is `insert`, if any. +pub fn array_of_insert(document: &CadDocument, insert: Handle) -> Option { + document.objects.iter().find_map(|(&handle, object)| { + let ObjectType::Associative(object) = object else { + return None; + }; + let AssociativeData::Action(action) = &object.data else { + return None; + }; + let array_body = body(document, action.action_body)?; + let (mut array_block, mut source_block, mut owns_insert) = + (Handle::NULL, Handle::NULL, false); + for link in &action.dependencies { + let Some(dependency) = dependency(document, link.dependency) else { + continue; + }; + match (dependency.is_read_dependency, dependency.is_write_dependency) { + (true, true) if dependency.dependent_on == insert => owns_insert = true, + (false, true) => array_block = dependency.dependent_on, + (true, false) if source_block.is_null() => { + source_block = dependency.dependent_on + } + _ => {} + } + } + let kind = match array_body.parameter_block.as_str() { + "AcDbAssocArrayRectangularParameters" => ArrayKind::Rectangular, + "AcDbAssocArrayPolarParameters" => ArrayKind::Polar, + "AcDbAssocArrayPathParameters" => ArrayKind::Path, + _ => return None, + }; + (owns_insert && !array_block.is_null() && !source_block.is_null()).then_some( + AssocArray { + insert, + action: handle, + body: action.action_body, + array_block, + source_block, + kind, + }, + ) + }) +} + +/// The value parameters of an array action: inline in the action (R2013+) +/// or in the body's parameter section (R2007). +pub fn value_params<'a>(document: &'a CadDocument, array: &AssocArray) -> &'a [AssocValueParam] { + match action(document, array.action) { + Some(action) if !action.values.is_empty() => &action.values, + _ => body(document, array.body).map_or(&[], |body| &body.parameter_body.values), + } +} + +/// The number a value parameter holds, whatever its stored type. +pub fn param_value(params: &[AssocValueParam], name: &str) -> Option { + let param = params.iter().find(|param| param.name == name)?; + match ¶m.variables.first()?.value.value { + AssocEvalValue::Real(value) => Some(*value), + AssocEvalValue::Long(value) => Some(f64::from(*value)), + AssocEvalValue::Short(value) => Some(f64::from(*value)), + AssocEvalValue::Byte(value) => Some(f64::from(*value)), + _ => None, + } +} + +/// Store `value` in a value parameter, keeping its stored type. +pub fn set_param_value(params: &mut [AssocValueParam], name: &str, value: f64) -> bool { + let Some(variable) = params + .iter_mut() + .find(|param| param.name == name) + .and_then(|param| param.variables.first_mut()) + else { + return false; + }; + variable.value.value = match variable.value.value { + AssocEvalValue::Long(_) => AssocEvalValue::Long(value.round() as i32), + AssocEvalValue::Short(_) => AssocEvalValue::Short(value.round() as i16), + AssocEvalValue::Byte(_) => AssocEvalValue::Byte(value.round() as u8), + _ => AssocEvalValue::Real(value), + }; + true +} + +/// The direction columns step along: the line of the action's "RowProfile" +/// parameter, X when the array has none. +pub fn column_axis(document: &CadDocument, array: &AssocArray) -> DVec3 { + let Some(action) = action(document, array.action) else { + return DVec3::X; + }; + action + .owned_parameters + .iter() + .find_map(|handle| { + let ObjectType::Associative(object) = document.objects.get(handle)? else { + return None; + }; + let AssociativeData::EdgeActionParam(edge) = &object.data else { + return None; + }; + if edge.single_dependency.action_param.name != "RowProfile" || edge.action_type != 19 + { + return None; + } + match edge.curve.get(1)? { + codec::objects::AssocCurveValue::Point(direction) => { + DVec3::new(direction.x, direction.y, direction.z).try_normalize() + } + _ => None, + } + }) + .unwrap_or(DVec3::X) +} + +/// The plane normal of an array: its "BaseNormal" vertex parameter, Z when +/// the array has none. +pub fn base_normal(document: &CadDocument, array: &AssocArray) -> DVec3 { + let Some(action) = action(document, array.action) else { + return DVec3::Z; + }; + action + .owned_parameters + .iter() + .find_map(|handle| { + let ObjectType::Associative(object) = document.objects.get(handle)? else { + return None; + }; + let AssociativeData::VertexActionParam(vertex) = &object.data else { + return None; + }; + if vertex.single_dependency.action_param.name != "BaseNormal" { + return None; + } + DVec3::new(vertex.point.x, vertex.point.y, vertex.point.z).try_normalize() + }) + .unwrap_or(DVec3::Z) +} + +/// Item placements of a rectangular array in array-local coordinates: +/// (column, row, level) and the offset of the item's base point. Columns +/// step along `axis`; rows run at AxesAngle from it about `normal`, and +/// levels along `normal`. +pub fn rectangular_items( + params: &[AssocValueParam], + axis: DVec3, + normal: DVec3, +) -> Vec<([i32; 3], DVec3)> { + let get = |name: &str, default: f64| param_value(params, name).unwrap_or(default); + let (columns, rows, levels) = ( + get("Items", 1.0).max(1.0) as i32, + get("Rows", 1.0).max(1.0) as i32, + get("Levels", 1.0).max(1.0) as i32, + ); + let column_step = axis * get("ItemSpacing", 0.0); + let axes = get("AxesAngle", std::f64::consts::FRAC_PI_2); + let row_axis = glam::DQuat::from_axis_angle(normal, axes) * axis; + let row_step = row_axis * get("RowSpacing", 0.0) + normal * get("RowElevation", 0.0); + let level_step = normal * get("LevelSpacing", 0.0); + let mut items = Vec::with_capacity((columns * rows * levels).max(0) as usize); + for level in 0..levels { + for row in 0..rows { + for column in 0..columns { + let offset = column_step * f64::from(column) + + row_step * f64::from(row) + + level_step * f64::from(level); + items.push(([column, row, level], offset)); + } + } + } + items +} + +/// An array item's placement in array-local coordinates, as stored. +pub fn stored_item_transform(item: &codec::objects::AssocArrayItem) -> DMat4 { + if item.uses_default_transform { + let offset = item.x_direction; + DMat4::from_translation(DVec3::new(offset.x, offset.y, offset.z)) + } else { + DMat4::from_cols_array(&item.transform).transpose() + } +} + +/// The in-plane X axis angles are measured from: world X for a plan array, +/// the arbitrary-axis direction otherwise. +fn plane_x(normal: DVec3) -> DVec3 { + if normal.x.abs() < 1.0 / 64.0 && normal.y.abs() < 1.0 / 64.0 { + DVec3::Y.cross(normal).normalize() + } else { + DVec3::Z.cross(normal).normalize() + } +} + +/// The centre of a polar array, recovered from its first item and its +/// Radius and StartAngle. +pub fn polar_center(document: &CadDocument, array: &AssocArray) -> Option { + let params = value_params(document, array); + let first = body(document, array.body)? + .items + .iter() + .find(|item| item.location == [0, 0, 0])?; + let normal = base_normal(document, array); + let x = plane_x(normal); + let y = normal.cross(x); + let start = param_value(params, "StartAngle").unwrap_or(0.0); + let radius = param_value(params, "Radius")?; + Some( + stored_item_transform(first).w_axis.truncate() + - (x * start.cos() + y * start.sin()) * radius, + ) +} + +/// Item placements of a polar array about `center`: each item turns about +/// the centre by its multiple of ItemSpacing (rotated with it unless +/// AlignItems is 0); rows step the radius out, levels step along the normal. +pub fn polar_items( + params: &[AssocValueParam], + center: DVec3, + normal: DVec3, +) -> Vec<([i32; 3], DMat4)> { + let get = |name: &str, default: f64| param_value(params, name).unwrap_or(default); + let (count, rows, levels) = ( + get("Items", 1.0).max(1.0) as i32, + get("Rows", 1.0).max(1.0) as i32, + get("Levels", 1.0).max(1.0) as i32, + ); + // ponytail: Direction 0 read as clockwise; no sample with 0 to confirm. + let sign = if get("Direction", 1.0) == 0.0 { -1.0 } else { 1.0 }; + let align = get("AlignItems", 1.0) != 0.0; + let (spacing, start, radius) = + (get("ItemSpacing", 0.0), get("StartAngle", 0.0), get("Radius", 0.0)); + let x = plane_x(normal); + let y = normal.cross(x); + let start_dir = x * start.cos() + y * start.sin(); + let mut items = Vec::with_capacity((count * rows * levels).max(0) as usize); + for level in 0..levels { + for row in 0..rows { + let ring = radius + f64::from(row) * get("RowSpacing", 0.0); + let lift = normal + * (f64::from(row) * get("RowElevation", 0.0) + + f64::from(level) * get("LevelSpacing", 0.0)); + for item in 0..count { + let turn = glam::DQuat::from_axis_angle(normal, sign * f64::from(item) * spacing); + let position = center + turn * (start_dir * ring) + lift; + let placement = if align { + DMat4::from_rotation_translation(turn, position) + } else { + DMat4::from_translation(position) + }; + items.push(([item, row, level], placement)); + } + } + } + items +} + +/// The rows the Properties palette shows for an array: (field, parameter, +/// label, kind) where kind 0 is a count, 1 a length and 2 an angle. +fn property_rows(kind: ArrayKind) -> &'static [(&'static str, &'static str, &'static str, u8)] { + match kind { + ArrayKind::Rectangular => &[ + ("assoc_array_columns", "Items", "Columns", 0), + ("assoc_array_column_spacing", "ItemSpacing", "Column spacing", 1), + ("assoc_array_rows", "Rows", "Rows", 0), + ("assoc_array_row_spacing", "RowSpacing", "Row spacing", 1), + ("assoc_array_levels", "Levels", "Levels", 0), + ("assoc_array_level_spacing", "LevelSpacing", "Level spacing", 1), + ], + ArrayKind::Polar => &[ + ("assoc_array_items", "Items", "Items", 0), + ("assoc_array_fill_angle", "FillAngle", "Fill angle", 2), + ("assoc_array_radius", "Radius", "Radius", 1), + ("assoc_array_rows", "Rows", "Rows", 0), + ("assoc_array_row_spacing", "RowSpacing", "Row spacing", 1), + ("assoc_array_levels", "Levels", "Levels", 0), + ("assoc_array_level_spacing", "LevelSpacing", "Level spacing", 1), + ], + ArrayKind::Path => &[ + ("assoc_array_items", "Items", "Items", 0), + ("assoc_array_item_spacing", "ItemSpacing", "Item spacing", 1), + ("assoc_array_rows", "Rows", "Rows", 0), + ("assoc_array_row_spacing", "RowSpacing", "Row spacing", 1), + ("assoc_array_levels", "Levels", "Levels", 0), + ("assoc_array_level_spacing", "LevelSpacing", "Level spacing", 1), + ], + } +} + +/// The Properties section of an associative array. Path arrays are shown +/// read-only: their items follow a curve this does not re-place yet. +pub fn property_section( + document: &CadDocument, + array: &AssocArray, +) -> crate::scene::model::object::PropSection { + use crate::entities::common::{format_angle, format_length}; + use crate::scene::model::object::{PropSection, PropValue, Property}; + let params = value_params(document, array); + let props = property_rows(array.kind) + .iter() + .filter_map(|&(field, name, label, kind)| { + let value = param_value(params, name)?; + let text = match kind { + 0 => format!("{}", value.round() as i64), + 1 => format_length(value), + _ => format_angle(value), + }; + Some(Property { + label: crate::t!(label).into_owned(), + field, + value: if array.kind == ArrayKind::Path { + PropValue::ReadOnly(text) + } else { + PropValue::EditText(text) + }, + }) + }) + .collect(); + let title = match array.kind { + ArrayKind::Rectangular => "Array (Rectangular)", + ArrayKind::Polar => "Array (Polar)", + ArrayKind::Path => "Array (Path)", + }; + PropSection { + title: crate::t!(title).into_owned(), + props, + } +} + +/// Write a Properties edit of an array row: the parameter changes and the +/// items are placed again. `text` is the typed value (counts, lengths in +/// drawing units, angles as typed angles). +pub fn apply_field( + scene: &mut crate::scene::Scene, + array: &AssocArray, + field: &str, + text: &str, +) -> Result<(), String> { + let Some(&(_, name, _, kind)) = + property_rows(array.kind).iter().find(|row| row.0 == field) + else { + return Err("unknown array field".into()); + }; + let value = match kind { + 0 => text + .trim() + .parse::() + .ok() + .filter(|v| *v >= 1.0 && *v <= 100_000.0) + .map(f64::round), + 1 => crate::entities::common::parse_typed_length(text), + _ => crate::entities::common::parse_typed_angle(text), + } + .filter(|v| v.is_finite()) + .ok_or("invalid value")?; + update(scene, array, &[(name, value)]) +} + +/// Change an array's parameters and place its items again: the item +/// INSERTs in the array block, the body's item records and the parameter +/// values move together, so the array stays associative on save. +pub fn update( + scene: &mut crate::scene::Scene, + array: &AssocArray, + changes: &[(&str, f64)], +) -> Result<(), String> { + use codec::objects::AssocArrayItem; + use codec::EntityType; + if array.kind == ArrayKind::Path { + return Err("path arrays cannot be edited yet".into()); + } + let document = &scene.document; + let mut params = value_params(document, array).to_vec(); + let center = match array.kind { + ArrayKind::Polar => polar_center(document, array).ok_or("array has no first item")?, + _ => DVec3::ZERO, + }; + for (name, value) in changes { + set_param_value(&mut params, name, *value); + } + if array.kind == ArrayKind::Polar + && changes.iter().any(|(name, _)| matches!(*name, "Items" | "FillAngle")) + { + let fill = param_value(¶ms, "FillAngle").unwrap_or(std::f64::consts::TAU); + let count = param_value(¶ms, "Items").unwrap_or(1.0).max(1.0); + let spacing = if (fill.abs() - std::f64::consts::TAU).abs() < 1e-9 { + fill / count + } else if count > 1.0 { + fill / (count - 1.0) + } else { + 0.0 + }; + set_param_value(&mut params, "ItemSpacing", spacing); + } + let normal = base_normal(document, array); + let placements: Vec<([i32; 3], DMat4)> = match array.kind { + ArrayKind::Rectangular => { + rectangular_items(¶ms, column_axis(document, array), normal) + .into_iter() + .map(|(location, offset)| (location, DMat4::from_translation(offset))) + .collect() + } + _ => polar_items(¶ms, center, normal), + }; + let current = body(document, array.body).ok_or("array body missing")?; + let template = current + .items + .iter() + .filter_map(|item| item.first_handle) + .find_map(|handle| match document.get_entity(handle) { + Some(EntityType::Insert(insert)) => Some(insert.clone()), + _ => None, + }) + .ok_or("array has no item reference")?; + let old_items: Vec = document + .block_records + .iter() + .find(|record| record.handle == array.array_block) + .map(|record| record.entity_handles.clone()) + .unwrap_or_default() + .into_iter() + .filter(|handle| matches!(document.get_entity(*handle), Some(EntityType::Insert(_)))) + .collect(); + + let document = &mut scene.document; + for handle in &old_items { + document.remove_entity(*handle); + } + let mut items = Vec::with_capacity(placements.len()); + let mut new_handles = Vec::with_capacity(placements.len()); + for (location, placement) in placements { + let mut insert = template.clone(); + insert.common.handle = Handle::NULL; + insert.common.owner_handle = array.array_block; + insert.common.reactors.clear(); + insert.common.xdictionary_handle = None; + let position = placement.w_axis.truncate(); + insert.insert_point = codec::types::Vector3::new(position.x, position.y, position.z); + insert.rotation = placement.x_axis.y.atan2(placement.x_axis.x); + let handle = document + .add_entity(EntityType::Insert(insert)) + .map_err(|error| error.to_string())?; + let turned = (placement.x_axis.truncate() - DVec3::X).length() > 1e-12 + || (placement.y_axis.truncate() - DVec3::Y).length() > 1e-12; + items.push(AssocArrayItem { + location, + flags: if turned { 12 } else { 8 }, + uses_default_transform: !turned, + x_direction: if turned { + codec::types::Vector3::ZERO + } else { + codec::types::Vector3::new(position.x, position.y, position.z) + }, + transform: if turned { + placement.transpose().to_cols_array() + } else { + [0.0; 16] + }, + first_handle: Some(handle), + ..Default::default() + }); + new_handles.push(handle); + } + if let Some(record) = document + .block_records + .iter_mut() + .find(|record| record.handle == array.source_block) + { + record.insert_handles.retain(|handle| !old_items.contains(handle)); + record.insert_handles.extend(new_handles); + } + let values_in_action = action(document, array.action).is_some_and(|a| !a.values.is_empty()); + if let Some(ObjectType::Associative(object)) = document.objects.get_mut(&array.body) { + let array_body = match &mut object.data { + AssociativeData::ArrayActionBody(body) => Some(body), + AssociativeData::ArrayModifyActionBody(modify) => Some(&mut modify.body), + _ => None, + }; + if let Some(array_body) = array_body { + array_body.items = items; + if !values_in_action { + array_body.parameter_body.values = params.clone(); + } + } + } + if values_in_action { + if let Some(ObjectType::Associative(object)) = document.objects.get_mut(&array.action) { + if let AssociativeData::Action(action) = &mut object.data { + action.values = params; + } + } + } + scene.bump_geometry(); + Ok(()) +} diff --git a/src/scene/mod.rs b/src/scene/mod.rs index f11b795ed..4546c5fe7 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -6,6 +6,7 @@ // view — camera, transforms, viewport, render pipeline driver // cache — block-definition and property caches pub mod annotative; +pub mod assoc_array; pub mod block_service; pub mod cache; pub mod convert;