diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index 6d2ac29c9..d79fd5109 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -908,6 +908,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: حدد كائن مقطع أو شغّل المقطع الحي. + .sectioncull-prepare-failed = SECTIONCULL: تعذر تجهيز كائن مقطوع؛ لم يتغير شيء. + .sectioncull-nothing-outside = SECTIONCULL: لا يوجد شيء خارج المقطع. + .sectioncull-result = SECTIONCULL: تم حذف __ocs_arg_erased__ كائن وقص __ocs_arg_cut__ عند حد المقطع. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: تم تمرير منحنى عبر __ocs_fmt_0__ نقطة. .splinefit-need-at-least-3-points = SPLINEFIT: يلزم 3 نقاط على الأقل. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: حدد خطًا متعددًا لتمرير منحنى عبره. diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index 51416c159..d63ece461 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -895,6 +895,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: изберете обект за сечение или включете живо сечение. + .sectioncull-prepare-failed = SECTIONCULL: изрязан обект не можа да бъде подготвен; нищо не е променено. + .sectioncull-nothing-outside = SECTIONCULL: извън сечението няма нищо. + .sectioncull-result = SECTIONCULL: изтрити __ocs_arg_erased__ обекта и изрязани __ocs_arg_cut__ по границата на сечението. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: сплайн прекаран през __ocs_fmt_0__ точки. .splinefit-need-at-least-3-points = SPLINEFIT: нужни са поне 3 точки. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: избери полилиния, през която да се прекара сплайн. diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index ed1c7361c..48b554740 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -895,6 +895,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: vyberte objekt řezu nebo zapněte živý řez. + .sectioncull-prepare-failed = SECTIONCULL: oříznutý objekt nelze připravit; nic nebylo změněno. + .sectioncull-nothing-outside = SECTIONCULL: mimo řez nic neleží. + .sectioncull-result = SECTIONCULL: vymazáno __ocs_arg_erased__ objekt(ů) a oříznuto __ocs_arg_cut__ na hranici řezu. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: proložení spline přes body __ocs_fmt_0__. .splinefit-need-at-least-3-points =SPLINEFIT: potřebujete alespoň 3 body. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: vyberte křivku pro proložení spline. diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index dca8a43f3..5178a577e 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -896,6 +896,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: Wählen Sie ein Schnittobjekt oder aktivieren Sie einen Live-Schnitt. + .sectioncull-prepare-failed = SECTIONCULL: ein geschnittenes Objekt konnte nicht vorbereitet werden; nichts wurde geändert. + .sectioncull-nothing-outside = SECTIONCULL: außerhalb des Schnitts liegt nichts. + .sectioncull-result = SECTIONCULL: __ocs_arg_erased__ Objekt(e) gelöscht und __ocs_arg_cut__ am Schnitt beschnitten. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: Passen Sie einen Spline durch __ocs_fmt_0__ Punkte. .splinefit-need-at-least-3-points = SPLINEFIT: mindestens 3 Punkte werden benötigt. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: Wählen Sie eine Polylinie, um eine Spline einzupassen. diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index 1fd456d23..976b4f633 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -897,6 +897,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: επιλέξτε αντικείμενο τομής ή ενεργοποιήστε ζωντανή τομή. + .sectioncull-prepare-failed = SECTIONCULL: ένα κομμένο αντικείμενο δεν προετοιμάστηκε· τίποτα δεν άλλαξε. + .sectioncull-nothing-outside = SECTIONCULL: τίποτα δεν βρίσκεται εκτός της τομής. + .sectioncull-result = SECTIONCULL: διαγράφηκαν __ocs_arg_erased__ αντικείμενα και κόπηκαν __ocs_arg_cut__ στο όριο της τομής. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: προσαρμογή spline μέσα από __ocs_fmt_0__ σημεία. .splinefit-need-at-least-3-points = SPLINEFIT: απαιτούνται τουλάχιστον 3 σημεία. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: επιλέξτε μια πολυγραμμή για προσαρμογή spline. diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index 2a0ba9794..9144b0527 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -894,6 +894,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: select a section object or turn on a live section. + .sectioncull-prepare-failed = SECTIONCULL: a cut object could not be prepared; nothing was changed. + .sectioncull-nothing-outside = SECTIONCULL: nothing lies outside the section. + .sectioncull-result = SECTIONCULL: erased __ocs_arg_erased__ object(s) and cut __ocs_arg_cut__ across the section. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: fit a spline through __ocs_fmt_0__ points. .splinefit-need-at-least-3-points = SPLINEFIT: need at least 3 points. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: select a polyline to fit a spline through. diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index 8905c5bad..18cd02a69 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -896,6 +896,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: seleccione un objeto de sección o active una sección dinámica. + .sectioncull-prepare-failed = SECTIONCULL: no se pudo preparar un objeto cortado; no se cambió nada. + .sectioncull-nothing-outside = SECTIONCULL: no hay nada fuera de la sección. + .sectioncull-result = SECTIONCULL: se borraron __ocs_arg_erased__ objeto(s) y se cortaron __ocs_arg_cut__ en el límite de la sección. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: se ajustó una spline por __ocs_fmt_0__ puntos. .splinefit-need-at-least-3-points = SPLINEFIT: se necesitan al menos 3 puntos. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: seleccione una polilínea por la que ajustar una spline. diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index 4fb9f5857..c1e6ddd4b 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -895,6 +895,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: valitse leikkausobjekti tai ota live-leikkaus käyttöön. + .sectioncull-prepare-failed = SECTIONCULL: leikattua objektia ei voitu valmistella; mitään ei muutettu. + .sectioncull-nothing-outside = SECTIONCULL: leikkauksen ulkopuolella ei ole mitään. + .sectioncull-result = SECTIONCULL: __ocs_arg_erased__ objekti(a) poistettu ja __ocs_arg_cut__ leikattu leikkauksen rajalla. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: sovita spline __ocs_fmt_0__-pisteiden läpi. .splinefit-need-at-least-3-points =SPLINEFIT: tarvitset vähintään 3 pistettä. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: valitse polyline sovittaaksesi splinin läpi. diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index 788e2d1d9..079c90a53 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -896,6 +896,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: sélectionnez un objet de coupe ou activez une coupe dynamique. + .sectioncull-prepare-failed = SECTIONCULL: un objet coupé n'a pas pu être préparé ; rien n'a été modifié. + .sectioncull-nothing-outside = SECTIONCULL: rien ne se trouve hors de la coupe. + .sectioncull-result = SECTIONCULL: __ocs_arg_erased__ objet(s) effacé(s) et __ocs_arg_cut__ coupé(s) à la limite de la coupe. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: adaptez une élingue à des points __ocs_fmt_0__. .splinefit-need-at-least-3-points = SPLINEFIT: nécessite au moins 3 points. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT : sélectionnez une polyligne pour l'adapter à une spline. diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index e86a264ed..b1e8b141f 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -884,6 +884,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: एक सेक्शन ऑब्जेक्ट चुनें या लाइव सेक्शन चालू करें। + .sectioncull-prepare-failed = SECTIONCULL: कटा हुआ ऑब्जेक्ट तैयार नहीं हो सका; कुछ नहीं बदला गया। + .sectioncull-nothing-outside = SECTIONCULL: सेक्शन के बाहर कुछ नहीं है। + .sectioncull-result = SECTIONCULL: __ocs_arg_erased__ ऑब्जेक्ट मिटाए गए और सेक्शन की सीमा पर __ocs_arg_cut__ काटे गए। .splinefit-fit-a-spline-through-n-points = SPLINEFIT: __ocs_fmt_0__ अंक के माध्यम से एक स्पैन फिट। .splinefit-need-at-least-3-points = SPLINEFIT: कम से कम 3 अंक की आवश्यकता है। .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: एक sline के माध्यम से फिट करने के लिए एक पॉलीलाइन का चयन करें। diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index 0985d048b..b570a4d74 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -900,6 +900,10 @@ common = .slice-result-commit-failed = SLICE: az egyik eredmény nem véglegesíthető; az összes forrásobjektum megmaradt. .slice-retained-update-failed = SLICE: az egyik megtartott eredmény nem frissíthető. .slice-created-results = SLICE: __ocs_arg_count__ eredményobjektum létrehozva. + .sectioncull-no-section = SECTIONCULL: válasszon metszetobjektumot, vagy kapcsolja be az élő metszetet. + .sectioncull-prepare-failed = SECTIONCULL: egy vágott objektumot nem sikerült előkészíteni; semmi sem változott. + .sectioncull-nothing-outside = SECTIONCULL: a metszeten kívül nincs semmi. + .sectioncull-result = SECTIONCULL: __ocs_arg_erased__ objektum törölve, __ocs_arg_cut__ levágva a metszet határán. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: illesszen be egy spline-t a __ocs_fmt_0__ pontokon. .splinefit-need-at-least-3-points = SPLINEFIT: legalább 3 pont szükséges. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: válasszon egy vonalláncot a spline átillesztéséhez. diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index 2b332964b..f258b26ad 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -895,6 +895,10 @@ common = .slice-result-commit-failed = SLICE: impossibile ottenere il risultato; gli oggetti originali sono rimasti come prima. .slice-retained-update-failed = SLICE: non riesco ad aggiornare il risultato ottenuto. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: selezionare un oggetto sezione o attivare una sezione dinamica. + .sectioncull-prepare-failed = SECTIONCULL: non è stato possibile preparare un oggetto tagliato; nulla è stato modificato. + .sectioncull-nothing-outside = SECTIONCULL: nulla si trova fuori dalla sezione. + .sectioncull-result = SECTIONCULL: cancellati __ocs_arg_erased__ oggetti e tagliati __ocs_arg_cut__ sul limite della sezione. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: adatta una spline attraverso i punti __ocs_fmt_0__. .splinefit-need-at-least-3-points =SPLINEFIT: servono almeno 3 punti. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: seleziona una polilinea attraverso la quale inserire una spline. diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index 79204dbf6..e9ecab250 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -886,6 +886,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: 断面オブジェクトを選択するか、ライブ断面をオンにしてください。 + .sectioncull-prepare-failed = SECTIONCULL: 切断したオブジェクトを準備できませんでした。何も変更されていません。 + .sectioncull-nothing-outside = SECTIONCULL: 断面の外側には何もありません。 + .sectioncull-result = SECTIONCULL: __ocs_arg_erased__ 個のオブジェクトを削除し、断面の境界で __ocs_arg_cut__ 個を切断しました。 .splinefit-fit-a-spline-through-n-points = SPLINEFIT: __ocs_fmt_0__ 点を通るスプラインを作成しました。 .splinefit-need-at-least-3-points = SPLINEFIT: 3 点以上必要です。 .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: スプラインを通すポリラインを選択してください。 diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index e8846e9f1..34af88034 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -895,6 +895,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: 단면 객체를 선택하거나 라이브 단면을 켜십시오. + .sectioncull-prepare-failed = SECTIONCULL: 잘린 객체를 준비할 수 없습니다. 아무것도 변경되지 않았습니다. + .sectioncull-nothing-outside = SECTIONCULL: 단면 밖에 있는 객체가 없습니다. + .sectioncull-result = SECTIONCULL: 객체 __ocs_arg_erased__개를 지우고 단면 경계에서 __ocs_arg_cut__개를 잘랐습니다. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: __ocs_fmt_0__ 점을 통해 스플라인을 맞춥니다. .splinefit-need-at-least-3-points =SPLINEFIT: 최소 3개의 포인트가 필요합니다. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: 스플라인에 맞게 폴리선을 선택합니다. diff --git a/locales/lo-LA/opencadstudio.ftl b/locales/lo-LA/opencadstudio.ftl index 5a4f3bb7c..ce1fa2137 100644 --- a/locales/lo-LA/opencadstudio.ftl +++ b/locales/lo-LA/opencadstudio.ftl @@ -901,6 +901,10 @@ common = .slice-result-commit-failed = SLICE: ບໍ່ສາມາດບັນທຶກຜົນຮັບໄດ້; ວັດຖຸຕົ້ນສະບັບທັງໝົດຍັງຖືກຮັກສາໄວ້. .slice-retained-update-failed = SLICE: ບໍ່ສາມາດອັບເດດຜົນຮັບທີ່ຮັກສາໄວ້ໄດ້. .slice-created-results = SLICE: ສ້າງ __ocs_arg_count__ ວັດຖຸຜົນຮັບແລ້ວ. + .sectioncull-no-section = SECTIONCULL: ເລືອກວັດຖຸພາກຕັດ ຫຼື ເປີດພາກຕັດສົດ. + .sectioncull-prepare-failed = SECTIONCULL: ບໍ່ສາມາດກະກຽມວັດຖຸທີ່ຖືກຕັດໄດ້; ບໍ່ມີຫຍັງປ່ຽນແປງ. + .sectioncull-nothing-outside = SECTIONCULL: ບໍ່ມີຫຍັງຢູ່ນອກພາກຕັດ. + .sectioncull-result = SECTIONCULL: ລຶບ __ocs_arg_erased__ ວັດຖຸ ແລະ ຕັດ __ocs_arg_cut__ ຢູ່ຂອບພາກຕັດ. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: ປັບເສັ້ນສະພລາຍຜ່ານ __ocs_fmt_0__ ຈຸດ. .splinefit-need-at-least-3-points = SPLINEFIT: ຕ້ອງການຢ່າງໜ້ອຍ 3 ຈຸດ. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: ເລືອກໂພລີລາຍເພື່ອປັບເສັ້ນສະພລາຍຜ່ານ. diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index f93aea618..6e83d91b9 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -894,6 +894,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: selecteer een doorsnedeobject of zet een live doorsnede aan. + .sectioncull-prepare-failed = SECTIONCULL: een gesneden object kon niet worden voorbereid; er is niets gewijzigd. + .sectioncull-nothing-outside = SECTIONCULL: er ligt niets buiten de doorsnede. + .sectioncull-result = SECTIONCULL: __ocs_arg_erased__ object(en) gewist en __ocs_arg_cut__ afgesneden op de doorsnede. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: pas een spline door __ocs_fmt_0__ punten. .splinefit-need-at-least-3-points = SPLINEFIT: minimaal 3 punten nodig. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: selecteer een polylijn om een spline door te passen. diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index c635f4201..689beb578 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -895,6 +895,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: wybierz obiekt przekroju lub włącz przekrój dynamiczny. + .sectioncull-prepare-failed = SECTIONCULL: nie udało się przygotować przeciętego obiektu; nic nie zmieniono. + .sectioncull-nothing-outside = SECTIONCULL: nic nie leży poza przekrojem. + .sectioncull-result = SECTIONCULL: usunięto __ocs_arg_erased__ obiekt(ów) i przycięto __ocs_arg_cut__ na granicy przekroju. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: dopasuj splajn przez punkty __ocs_fmt_0__. .splinefit-need-at-least-3-points =SPLINEFIT: potrzebne są co najmniej 3 punkty. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: wybierz polilinię, przez którą ma zostać dopasowany splajn. diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index 676a14478..3f2055d88 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -896,6 +896,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: selecione um objeto de seção ou ative uma seção dinâmica. + .sectioncull-prepare-failed = SECTIONCULL: não foi possível preparar um objeto cortado; nada foi alterado. + .sectioncull-nothing-outside = SECTIONCULL: nada está fora da seção. + .sectioncull-result = SECTIONCULL: __ocs_arg_erased__ objeto(s) apagado(s) e __ocs_arg_cut__ cortado(s) no limite da seção. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: spline ajustada através de __ocs_fmt_0__ pontos. .splinefit-need-at-least-3-points = SPLINEFIT: são necessários pelo menos 3 pontos. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: selecione uma polilinha através da qual ajustar uma spline. diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index b463a4cb8..6d05b4a86 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -899,6 +899,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: выберите объект сечения или включите динамическое сечение. + .sectioncull-prepare-failed = SECTIONCULL: не удалось подготовить обрезанный объект; ничего не изменено. + .sectioncull-nothing-outside = SECTIONCULL: за пределами сечения ничего нет. + .sectioncull-result = SECTIONCULL: удалено объектов: __ocs_arg_erased__, обрезано по границе сечения: __ocs_arg_cut__. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: проведите сплин через точки __ocs_fmt_0__. .splinefit-need-at-least-3-points = SPLINEFIT: необходимо не менее 3 баллов. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: выберите полилин, чтобы соответствовать сплину. diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index 72f197167..b1bb5b4c9 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -884,6 +884,10 @@ common = .slice-result-commit-failed = SLICE: Bir sonuç işlenemedi; tüm kaynak nesneler korundu. .slice-retained-update-failed = SLICE: Korunan sonuç güncellenemedi. .slice-created-results = SLICE: __ocs_arg_count__ sonuç nesnesi oluşturuldu. + .sectioncull-no-section = SECTIONCULL: bir kesit nesnesi seçin veya canlı kesiti açın. + .sectioncull-prepare-failed = SECTIONCULL: kesilen bir nesne hazırlanamadı; hiçbir şey değiştirilmedi. + .sectioncull-nothing-outside = SECTIONCULL: kesitin dışında kalan bir şey yok. + .sectioncull-result = SECTIONCULL: __ocs_arg_erased__ nesne silindi, kesit sınırındaki __ocs_arg_cut__ nesne kesildi. .splinefit-fit-a-spline-through-n-points = SPLINEFIT: __ocs_fmt_0__ noktadan geçen bir spline uyduruldu. .splinefit-need-at-least-3-points = SPLINEFIT: En az 3 nokta gerekir. .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT: İçinden spline geçirilecek bir çoklu çizgi seçin. diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index a7aad2382..09c0585f1 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -883,6 +883,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: 请选择截面对象或打开活动截面。 + .sectioncull-prepare-failed = SECTIONCULL: 无法准备剪切后的对象;未做任何更改。 + .sectioncull-nothing-outside = SECTIONCULL: 截面之外没有任何对象。 + .sectioncull-result = SECTIONCULL: 已删除 __ocs_arg_erased__ 个对象,并在截面边界处剪切 __ocs_arg_cut__ 个。 .splinefit-fit-a-spline-through-n-points = SPLINEFIT: 匹配一条通过__ocs_fmt_0__点的相片。 .splinefit-need-at-least-3-points = SPLINEFIT:至少需要3个点。 .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT:选择一条多线以适应通过的分线。 diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index 7aead8aac..0307994fe 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -895,6 +895,10 @@ common = .slice-result-commit-failed = SLICE: a result could not be committed; all source objects were retained. .slice-retained-update-failed = SLICE: a retained result could not be updated. .slice-created-results = SLICE: created __ocs_arg_count__ result object(s). + .sectioncull-no-section = SECTIONCULL: 請選取剖面物件或開啟即時剖面。 + .sectioncull-prepare-failed = SECTIONCULL: 無法準備剪切後的物件;未做任何變更。 + .sectioncull-nothing-outside = SECTIONCULL: 剖面之外沒有任何物件。 + .sectioncull-result = SECTIONCULL: 已刪除 __ocs_arg_erased__ 個物件,並在剖面邊界剪切 __ocs_arg_cut__ 個。 .splinefit-fit-a-spline-through-n-points = SPLINEFIT: 匹配一條通過__ocs_fmt_0__點的相片。 .splinefit-need-at-least-3-points = SPLINEFIT:至少需要3個點。 .splinefit-select-a-polyline-to-fit-a-spline-th = SPLINEFIT:選擇一條多線以適應通過的分線。 diff --git a/src/app/commands/draw.rs b/src/app/commands/draw.rs index d4fb22f16..ccdb7ba5c 100644 --- a/src/app/commands/draw.rs +++ b/src/app/commands/draw.rs @@ -2148,6 +2148,11 @@ impl OpenCADStudio { self.tabs[i].active_cmd = Some(Box::new(subtract)); } + // SECTIONCULL — erase what lies outside a section object. + "SECTIONCULL" => { + return Some(self.section_cull()); + } + // INTERFERE — non-destructive intersect: solid from the overlap. "INTERFERE" => { return Some(self.solid_interfere()); diff --git a/src/app/commands/mod.rs b/src/app/commands/mod.rs index 0ac001f53..1d1d36822 100644 --- a/src/app/commands/mod.rs +++ b/src/app/commands/mod.rs @@ -621,6 +621,7 @@ inventory::submit!(crate::command::CommandRegistration { "SL", "INTERFERE", "INF", + "SECTIONCULL", "PRESSPULL", "THICKEN", "3DROTATE", diff --git a/src/app/model_ops.rs b/src/app/model_ops.rs index c7a44f5ba..486d45c40 100644 --- a/src/app/model_ops.rs +++ b/src/app/model_ops.rs @@ -225,6 +225,8 @@ fn subtract_bodies( Ok(result) } +inventory::submit!(crate::command::CommandRegistration { names: &["SECTIONCULL"] }); + fn entity_with_boolean_body(mut source: EntityType, body: &Body) -> Option { let document = crate::scene::convert::acis_export::solid_to_sat(body)?; let wires = solid_model::edge_wires(body); @@ -2073,6 +2075,74 @@ impl super::OpenCADStudio { self.solid_slice(&handles, plane, keep_point) } + /// SECTIONCULL — keep only what lies inside the selected section object + /// (or the live section): bodies are cut to it, open meshes clipped, and + /// everything wholly outside it erased. One undo step. + pub(super) fn section_cull(&mut self) -> Task { + let i = self.active_tab; + let Some(section) = self.tabs[i].scene.cull_section() else { + self.command_line.push_error( + crate::t!("SECTIONCULL: select a section object or turn on a live section.") + .as_ref(), + ); + return Task::none(); + }; + let Some(cull) = self.tabs[i].scene.section_cull(section) else { + return Task::none(); + }; + let mut cut = Vec::with_capacity(cull.cut.len()); + for (handle, body) in cull.cut { + let scene = &self.tabs[i].scene; + let entity = scene + .document + .get_entity(handle) + .cloned() + .and_then(|source| entity_with_boolean_body(source, &body)); + let display = scene + .prepare_solid_model_display(handle, &body) + .filter(|display| display.0.complete); + let (Some(entity), Some(display)) = (entity, display) else { + self.command_line.push_error( + crate::t!( + "SECTIONCULL: a cut object could not be prepared; nothing was changed." + ) + .as_ref(), + ); + return Task::none(); + }; + cut.push((handle, entity, body, display)); + } + let changed = cut.len() + cull.clipped.len() + cull.outside.len(); + if changed == 0 { + self.command_line + .push_output(crate::t!("SECTIONCULL: nothing lies outside the section.").as_ref()); + return Task::none(); + } + self.push_undo_snapshot(i, "SECTIONCULL"); + let scene = &mut self.tabs[i].scene; + for (handle, entity, body, display) in cut { + scene.delete_solid_history(handle); + scene.update_entity(entity); + scene.register_prepared_solid_model(handle, body, display); + } + for mesh in cull.clipped { + scene.update_entity(mesh); + } + scene.erase_entities(&cull.outside); + scene.deselect_all(); + self.tabs[i].dirty = true; + self.refresh_properties(); + self.command_line.push_output( + crate::t!( + "SECTIONCULL: erased %{erased} object(s) and cut %{cut} across the section.", + erased = cull.outside.len(), + cut = changed - cull.outside.len() + ) + .as_ref(), + ); + Task::none() + } + /// INTERFERE — create a solid from the overlap of the two selected solids, /// leaving the originals in place (a non-destructive boolean intersect). pub(super) fn solid_interfere(&mut self) -> Task { diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index 4a4745e31..bb757641b 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -2885,6 +2885,10 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static "SLICE: a result could not be committed; all source objects were retained." => Some(("common", "slice-result-commit-failed")), "SLICE: a retained result could not be updated." => Some(("common", "slice-retained-update-failed")), "SLICE: created %{count} result object(s)." => Some(("common", "slice-created-results")), + "SECTIONCULL: a cut object could not be prepared; nothing was changed." => Some(("common", "sectioncull-prepare-failed")), + "SECTIONCULL: erased %{erased} object(s) and cut %{cut} across the section." => Some(("common", "sectioncull-result")), + "SECTIONCULL: nothing lies outside the section." => Some(("common", "sectioncull-nothing-outside")), + "SECTIONCULL: select a section object or turn on a live section." => Some(("common", "sectioncull-no-section")), "SOLID Specify first point:" => Some(("draw", "solid-specify-first-point")), "SOLID Specify fourth point:" => Some(("draw", "solid-specify-fourth-point")), "SOLID Specify second point:" => Some(("draw", "solid-specify-second-point")), diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 8f19519e2..3cf1c1779 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -8,6 +8,7 @@ pub mod annotative; pub mod assoc_array; pub mod compare; +pub mod section_cull; pub mod block_service; pub mod cache; pub mod convert; @@ -8899,16 +8900,29 @@ impl Scene { slice_depth: Option, body_to_world: Option<&codec::types::Transform>, ) -> Result, ()> { - let Some((origin, tangent, vertical, viewing)) = section_frame(data) else { - return Err(()); - }; - let front = section_plane(origin, tangent, viewing, body_to_world).ok_or(())?; - let mut clipped = keep_section_positive(body, front)?; - let Some(mut current) = clipped.take() else { - return Ok(None); - }; + let planes = Self::section_planes(data, slice_depth, body_to_world).ok_or(())?; + let mut current = body.clone(); + for plane in planes { + match keep_section_positive(¤t, plane)? { + Some(next) => current = next, + None => return Ok(None), + } + } + Ok(Some(current)) + } + + /// The planes bounding what section `data` keeps, each facing inward: + /// the section plane, then the back of a slice, the ends of a boundary + /// and the top and bottom of a volume. + fn section_planes( + data: &codec::entities::SectionObjectData, + slice_depth: Option, + body_to_world: Option<&codec::types::Transform>, + ) -> Option> { + let (origin, tangent, vertical, viewing) = section_frame(data)?; + let mut planes = vec![section_plane(origin, tangent, viewing, body_to_world)?]; if data.state == 1 && slice_depth.is_none() { - return Ok(Some(current)); + return Some(planes); } let depth = slice_depth.unwrap_or_else(|| { @@ -8923,82 +8937,44 @@ impl Scene { }) }); if depth <= 1e-12 { - return Ok(Some(current)); + return Some(planes); } - let back = - section_plane(origin + viewing * depth, tangent, -viewing, body_to_world).ok_or(())?; - let Some(next) = keep_section_positive(¤t, back)? else { - return Ok(None); - }; - current = next; - + planes.push(section_plane( + origin + viewing * depth, + tangent, + -viewing, + body_to_world, + )?); if data.state == 1 { - return Ok(Some(current)); + return Some(planes); } - let span = data - .vertices - .first() - .zip(data.vertices.last()) - .map_or(0.0, |(first, last)| { - (glam::DVec3::new(last.x, last.y, last.z) - - glam::DVec3::new(first.x, first.y, first.z)) - .length() - }); - if span <= 1e-12 { - return Ok(Some(current)); + let first = data.vertices.first()?; + let last = data.vertices.last()?; + let first = glam::DVec3::new(first.x, first.y, first.z); + let last = glam::DVec3::new(last.x, last.y, last.z); + if (last - first).length() <= 1e-12 { + return Some(planes); } - - let first = data - .vertices - .first() - .map(|point| glam::DVec3::new(point.x, point.y, point.z)) - .ok_or(())?; - let last = data - .vertices - .last() - .map(|point| glam::DVec3::new(point.x, point.y, point.z)) - .ok_or(())?; - for plane in [ - section_plane(first, vertical, tangent, body_to_world), - section_plane(last, vertical, -tangent, body_to_world), - ] { - let Some(plane) = plane else { - return Err(()); - }; - let Some(next) = keep_section_positive(¤t, plane)? else { - return Ok(None); - }; - current = next; - } - + planes.push(section_plane(first, vertical, tangent, body_to_world)?); + planes.push(section_plane(last, vertical, -tangent, body_to_world)?); if data.state != 4 { - return Ok(Some(current)); + return Some(planes); } - for plane in [ - section_plane( - origin - vertical * data.bottom_height, - tangent, - vertical, - body_to_world, - ), - section_plane( - origin + vertical * data.top_height, - tangent, - -vertical, - body_to_world, - ), - ] { - let Some(plane) = plane else { - return Err(()); - }; - let Some(next) = keep_section_positive(¤t, plane)? else { - return Ok(None); - }; - current = next; - } - Ok(Some(current)) + planes.push(section_plane( + origin - vertical * data.bottom_height, + tangent, + vertical, + body_to_world, + )?); + planes.push(section_plane( + origin + vertical * data.top_height, + tangent, + -vertical, + body_to_world, + )?); + Some(planes) } /// True when `layer` is turned off or frozen — entities on it never render. diff --git a/src/scene/section_cull.rs b/src/scene/section_cull.rs new file mode 100644 index 000000000..66ef771ea --- /dev/null +++ b/src/scene/section_cull.rs @@ -0,0 +1,229 @@ +//! SECTIONCULL: keep only what lies inside a section object — the part a +//! live section shows — and remove the rest for good. Solids, surfaces and +//! closed meshes are cut to it, open meshes are clipped face by face, and +//! every other object wholly outside it is erased. Objects across its +//! boundary that cannot be cut stay whole. + +use codec::{EntityType, Handle}; +use glam::DVec3; +use rustc_hash::FxHashMap; + +use super::Scene; + +/// What culling to a section does to the space it lives in. +#[derive(Default)] +pub struct SectionCull { + /// Bodies the section crosses, with what stays of each. + pub cut: Vec<(Handle, kernel::brep::Body)>, + /// Open meshes the section crosses, clipped to it. + pub clipped: Vec, + /// Objects wholly outside the section. + pub outside: Vec, +} + +enum Place { + Inside, + Outside, + Across, +} + +const TOLERANCE: f64 = 1e-9; + +fn place(planes: &[kernel::space::Plane], points: &[[f64; 3]]) -> Place { + let mut inside = true; + for plane in planes { + let behind = points + .iter() + .filter(|point| plane.distance_to(**point).unwrap_or(0.0) < -TOLERANCE) + .count(); + if behind == points.len() { + return Place::Outside; + } + inside &= behind == 0; + } + if inside { + Place::Inside + } else { + Place::Across + } +} + +fn same_extent(a: &kernel::brep::Body, b: &kernel::brep::Body) -> bool { + match (kernel::brep::body_bounds(a), kernel::brep::body_bounds(b)) { + (Some(a), Some(b)) => (0..3).all(|axis| { + (a.min[axis] - b.min[axis]).abs() <= 1e-7 && (a.max[axis] - b.max[axis]).abs() <= 1e-7 + }), + _ => false, + } +} + +impl Scene { + /// The section SECTIONCULL works with: the selected section object, or + /// else the live section of the current space. + pub fn cull_section(&self) -> Option { + let is_section = |handle: &Handle| { + matches!( + self.document.get_entity(*handle), + Some(EntityType::Extended(extended)) + if matches!( + extended.data, + codec::entities::ExtendedEntityData::SectionObject(_) + ) + ) + }; + if let Some(handle) = self.selected_handles_in_order().into_iter().find(is_section) { + return Some(handle); + } + let block = self.current_layout_block_handle(); + self.document + .entities() + .filter(|entity| match entity { + EntityType::Extended(extended) => match &extended.data { + codec::entities::ExtendedEntityData::SectionObject(data) => { + let owner = extended.common.owner_handle; + data.flags & 1 != 0 + && !extended.common.invisible + && (owner.is_null() || owner == block) + } + _ => false, + }, + _ => false, + }) + .map(|entity| entity.common().handle) + .last() + } + + /// Plan culling the current space to section object `section`; `None` + /// when it is not a section object. + pub fn section_cull(&self, section: Handle) -> Option { + let Some(EntityType::Extended(extended)) = self.document.get_entity(section) else { + return None; + }; + let codec::entities::ExtendedEntityData::SectionObject(data) = &extended.data else { + return None; + }; + let slice_depth = crate::entities::extended::section_is_slice(extended).then(|| { + crate::entities::extended::section_slice_depth(extended).unwrap_or(0.0) + }); + let planes = Self::section_planes(data, slice_depth, None)?; + + // Every drawn point of every object in the space, from its wires and + // its shaded mesh. + let block = self.current_layout_block_handle(); + let mut points: FxHashMap> = FxHashMap::default(); + let wires = self.wires_for_block_culled( + block, + None, + None, + None, + None, + None, + true, + None, + ); + for wire in &wires { + let Some(handle) = Self::handle_from_wire_name(&wire.name) else { + continue; + }; + let entry = points.entry(handle).or_default(); + for (index, &[x, y, z]) in wire.points.iter().enumerate() { + let [lx, ly, lz] = wire.points_low.get(index).copied().unwrap_or([0.0; 3]); + let point = DVec3::new( + f64::from(x) + f64::from(lx), + f64::from(y) + f64::from(ly), + f64::from(z) + f64::from(lz), + ); + if point.is_finite() { + entry.push(point.to_array()); + } + } + } + for set in self.interaction_meshes_arc().iter() { + let handle = set.entity_handle(); + let (Some(handle), Some(aabb)) = (handle, super::mesh_interaction_aabb(set)) else { + continue; + }; + let entry = points.entry(handle).or_default(); + for corner in 0..8 { + entry.push([ + aabb[if corner & 1 == 0 { 0 } else { 3 }], + aabb[if corner & 2 == 0 { 1 } else { 4 }], + aabb[if corner & 4 == 0 { 2 } else { 5 }], + ]); + } + } + + let mut cull = SectionCull::default(); + // A live section hides what lies wholly outside it, so the space's + // own objects are walked too. + let mut handles: Vec = points + .keys() + .copied() + .chain( + self.document + .entities() + .filter(|entity| entity.common().owner_handle == block) + .map(|entity| entity.common().handle), + ) + .collect(); + handles.sort_unstable_by_key(|handle| handle.value()); + handles.dedup(); + for handle in handles { + if handle == section || self.is_layer_locked(handle) { + continue; + } + let Some(entity) = self.document.get_entity(handle) else { + continue; + }; + // Bodies are cut with the kernel: their drawn wires may already + // show the live cut, so they say nothing about the source. + if let Some(body) = self.section_source_body(handle) { + match Self::section_body(&body, data, slice_depth, None) { + Ok(None) => cull.outside.push(handle), + Ok(Some(kept)) if !same_extent(&body, &kept) => cull.cut.push((handle, kept)), + _ => {} + } + continue; + } + if let Some((vertices, _)) = crate::entities::mesh::mesh_polygons(entity) { + match place(&planes, &vertices) { + Place::Outside => cull.outside.push(handle), + Place::Inside => {} + Place::Across => { + let mut mesh = entity.clone(); + for plane in &planes { + let Some((vertices, faces)) = + crate::entities::mesh::mesh_polygons(&mesh) + else { + break; + }; + let side = |point: [f64; 3]| plane.distance_to(point).unwrap_or(0.0); + if vertices.iter().all(|point| side(*point) >= -TOLERANCE) { + continue; + } + let Some(mut clipped) = crate::entities::mesh::clipped_mesh( + &vertices, + &faces, + side, + true, + mesh.common(), + ) else { + break; + }; + clipped.common.handle = handle; + mesh = EntityType::Mesh(clipped); + } + cull.clipped.push(mesh); + } + } + continue; + } + if let Some(points) = points.get(&handle) { + if matches!(place(&planes, points), Place::Outside) { + cull.outside.push(handle); + } + } + } + Some(cull) + } +}