diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index fb0f0f506..8701aca70 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -1567,6 +1567,8 @@ common = .nav-style-cad = CAD: ‏Shift + الزر الأوسط للدوران .nav-style-blender = Blender: الزر الأوسط للدوران، Shift للتحريك .nav-style-catia = CATIA: الزر الأوسط + الأيسر للدوران + .dynamic-ucs-on = نظام الإحداثيات الديناميكي: تشغيل + .dynamic-ucs-off = نظام الإحداثيات الديناميكي: إيقاف .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = لوحة اللمس: التمرير يحرك العرض، Ctrl+تمرير أو القرص يكبّر .interface-scale = مقياس الواجهة .zoom-factor = معامل التكبير diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index 59cfd1106..9021c3cb6 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -1554,6 +1554,8 @@ common = .nav-style-cad = CAD: Shift + среден бутон завърта .nav-style-blender = Blender: среден бутон завърта, Shift премества .nav-style-catia = CATIA: среден + ляв бутон завърта + .dynamic-ucs-on = Динамична ПКС: вкл. + .dynamic-ucs-off = Динамична ПКС: изкл. .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Тъчпад: превъртането мести изгледа, Ctrl+превъртане или щипване мащабира .interface-scale = Мащаб на интерфейса .zoom-factor = Коефициент на мащабиране diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index 1c3e36f2b..f0023b21a 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -1554,6 +1554,8 @@ common = .nav-style-cad = CAD: Shift + prostřední tlačítko otáčí .nav-style-blender = Blender: prostřední tlačítko otáčí, Shift posouvá .nav-style-catia = CATIA: prostřední + levé tlačítko otáčí + .dynamic-ucs-on = Dynamický USS: zapnuto + .dynamic-ucs-off = Dynamický USS: vypnuto .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Touchpad: posun posouvá pohled, Ctrl+posun nebo sevření zvětšuje .interface-scale = Měřítko rozhraní .zoom-factor = Faktor zoomu diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index 3e321eea9..59f8b9705 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -1555,6 +1555,8 @@ common = .nav-style-cad = CAD: Umschalt + mittlere Taste dreht .nav-style-blender = Blender: mittlere Taste dreht, Umschalt verschiebt .nav-style-catia = CATIA: mittlere + linke Taste dreht + .dynamic-ucs-on = Dynamisches BKS: ein + .dynamic-ucs-off = Dynamisches BKS: aus .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Touchpad: Scrollen verschiebt, Strg+Scrollen oder Zusammenziehen zoomt .interface-scale = Oberflächenskalierung .zoom-factor = Zoomfaktor diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index 56e99e5c4..60a8c6969 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -1556,6 +1556,8 @@ common = .nav-style-cad = CAD: Shift + μεσαίο πλήκτρο περιστρέφει .nav-style-blender = Blender: μεσαίο πλήκτρο περιστρέφει, Shift μετακινεί .nav-style-catia = CATIA: μεσαίο + αριστερό πλήκτρο περιστρέφει + .dynamic-ucs-on = Δυναμικό UCS: ενεργό + .dynamic-ucs-off = Δυναμικό UCS: ανενεργό .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Επιφάνεια αφής: η κύλιση μετακινεί, Ctrl+κύλιση ή τσίμπημα κάνει ζουμ .interface-scale = Κλίμακα διεπαφής .zoom-factor = Συντελεστής ζουμ diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index 38da05fc8..a2ffad1c1 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -1555,6 +1555,8 @@ common = .nav-style-cad = CAD: Shift + middle button orbits .nav-style-blender = Blender: middle button orbits, Shift pans .nav-style-catia = CATIA: middle + left button orbits + .dynamic-ucs-on = Dynamic UCS: on + .dynamic-ucs-off = Dynamic UCS: off .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Touchpad: scroll pans, Ctrl+scroll or pinch zooms .interface-scale = Interface scale .zoom-factor = Zoom factor diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index cd1336f55..919bc64cb 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -1555,6 +1555,8 @@ common = .nav-style-cad = CAD: Mayús + botón central orbita .nav-style-blender = Blender: botón central orbita, Mayús desplaza .nav-style-catia = CATIA: botón central + izquierdo orbita + .dynamic-ucs-on = SCP dinámico: activado + .dynamic-ucs-off = SCP dinámico: desactivado .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Panel táctil: el desplazamiento encuadra, Ctrl+desplazamiento o pellizco hace zoom .interface-scale = Escala de la interfaz .zoom-factor = Factor de zoom diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index 4be36fa15..fb3e1d5d1 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -1554,6 +1554,8 @@ common = .nav-style-cad = CAD: Vaihto + keskipainike kiertää .nav-style-blender = Blender: keskipainike kiertää, Vaihto panoroi .nav-style-catia = CATIA: keski- + vasen painike kiertää + .dynamic-ucs-on = Dynaaminen UCS: päällä + .dynamic-ucs-off = Dynaaminen UCS: pois .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Kosketuslevy: vieritys panoroi, Ctrl+vieritys tai nipistys zoomaa .interface-scale = Käyttöliittymän skaalaus .zoom-factor = Zoomauskerroin diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index ff19da37c..e9dcfdcde 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -1555,6 +1555,8 @@ common = .nav-style-cad = CAO : Maj + bouton du milieu fait pivoter .nav-style-blender = Blender : bouton du milieu fait pivoter, Maj déplace .nav-style-catia = CATIA : boutons du milieu + gauche font pivoter + .dynamic-ucs-on = SCU dynamique: activé + .dynamic-ucs-off = SCU dynamique: désactivé .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Pavé tactile : le défilement déplace, Ctrl+défilement ou pincement zoome .interface-scale = Échelle de l'interface .zoom-factor = Facteur de zoom diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index 94f157985..45dfa6060 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -1543,6 +1543,8 @@ common = .nav-style-cad = CAD: Shift + मध्य बटन घुमाता है .nav-style-blender = Blender: मध्य बटन घुमाता है, Shift खिसकाता है .nav-style-catia = CATIA: मध्य + बायाँ बटन घुमाता है + .dynamic-ucs-on = डायनामिक UCS: चालू + .dynamic-ucs-off = डायनामिक UCS: बंद .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = टचपैड: स्क्रॉल पैन करता है, Ctrl+स्क्रॉल या पिंच ज़ूम करता है .interface-scale = इंटरफ़ेस स्केल .zoom-factor = ज़ूम गुणक diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index 76248da27..e61af14b8 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -1560,6 +1560,8 @@ common = .nav-style-cad = CAD: Shift + középső gomb forgat .nav-style-blender = Blender: középső gomb forgat, Shift mozgat .nav-style-catia = CATIA: középső + bal gomb forgat + .dynamic-ucs-on = Dinamikus FKR: be + .dynamic-ucs-off = Dinamikus FKR: ki .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Érintőpad: a görgetés mozgat, a Ctrl+görgetés vagy csippentés nagyít .interface-scale = Felület mérete .zoom-factor = Nagyítási tényező diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index 6c19f8bdb..d20780e4b 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -1554,6 +1554,8 @@ common = .nav-style-cad = CAD: Maiusc + tasto centrale ruota .nav-style-blender = Blender: tasto centrale ruota, Maiusc sposta .nav-style-catia = CATIA: tasto centrale + sinistro ruota + .dynamic-ucs-on = UCS dinamico: attivo + .dynamic-ucs-off = UCS dinamico: disattivo .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Touchpad: lo scorrimento sposta la vista, Ctrl+scorrimento o pizzico esegue lo zoom .interface-scale = Scala dell'interfaccia .zoom-factor = Fattore di zoom diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index f2a8dbf96..da6ef89fe 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -1545,6 +1545,8 @@ common = .nav-style-cad = CAD: Shift + 中ボタンで回転 .nav-style-blender = Blender: 中ボタンで回転、Shift で画面移動 .nav-style-catia = CATIA: 中 + 左ボタンで回転 + .dynamic-ucs-on = ダイナミック UCS: オン + .dynamic-ucs-off = ダイナミック UCS: オフ .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = タッチパッド: スクロールで画面移動、Ctrl+スクロールまたはピンチでズーム .interface-scale = インターフェースの拡大率 .zoom-factor = ズーム倍率 diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index ddc8d622a..e8fec7108 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -1554,6 +1554,8 @@ common = .nav-style-cad = CAD: Shift + 가운데 버튼으로 회전 .nav-style-blender = Blender: 가운데 버튼으로 회전, Shift로 이동 .nav-style-catia = CATIA: 가운데 + 왼쪽 버튼으로 회전 + .dynamic-ucs-on = 동적 UCS: 켜짐 + .dynamic-ucs-off = 동적 UCS: 꺼짐 .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = 터치패드: 스크롤은 화면 이동, Ctrl+스크롤 또는 핀치는 확대/축소 .interface-scale = 인터페이스 배율 .zoom-factor = 줌 배율 diff --git a/locales/lo-LA/opencadstudio.ftl b/locales/lo-LA/opencadstudio.ftl index a1af519e0..1fe49c396 100644 --- a/locales/lo-LA/opencadstudio.ftl +++ b/locales/lo-LA/opencadstudio.ftl @@ -1560,6 +1560,8 @@ common = .nav-style-cad = CAD: Shift + ປຸ່ມກາງ ໝຸນ .nav-style-blender = Blender: ປຸ່ມກາງ ໝຸນ, Shift ເລື່ອນ .nav-style-catia = CATIA: ປຸ່ມກາງ + ຊ້າຍ ໝຸນ + .dynamic-ucs-on = UCS ແບບໄດນາມິກ: ເປີດ + .dynamic-ucs-off = UCS ແບບໄດນາມິກ: ປິດ .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = ທັດແພດ: ເລື່ອນເພື່ອຍ້າຍມຸມມອງ, Ctrl+ເລື່ອນ ຫຼື ບີບເພື່ອຊູມ .interface-scale = ຂະໜາດສ່ວນຕິດຕໍ່ .zoom-factor = ຕົວຄູນການຊູມ diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index 7aa044e93..6e34190f4 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -1553,6 +1553,8 @@ common = .nav-style-cad = CAD: Shift + middelste knop draait .nav-style-blender = Blender: middelste knop draait, Shift verschuift .nav-style-catia = CATIA: middelste + linkerknop draait + .dynamic-ucs-on = Dynamisch GCS: aan + .dynamic-ucs-off = Dynamisch GCS: uit .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Touchpad: scrollen verschuift, Ctrl+scrollen of knijpen zoomt .interface-scale = Interfaceschaal .zoom-factor = Zoomfactor diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index 23ca1cfbd..5afc7c700 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -1554,6 +1554,8 @@ common = .nav-style-cad = CAD: Shift + środkowy przycisk obraca .nav-style-blender = Blender: środkowy przycisk obraca, Shift przesuwa .nav-style-catia = CATIA: środkowy + lewy przycisk obraca + .dynamic-ucs-on = Dynamiczny LUW: wł. + .dynamic-ucs-off = Dynamiczny LUW: wył. .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Touchpad: przewijanie przesuwa widok, Ctrl+przewijanie lub szczypanie powiększa .interface-scale = Skala interfejsu .zoom-factor = Współczynnik powiększenia diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index 00dc78403..ecbf12fe2 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -1555,6 +1555,8 @@ common = .nav-style-cad = CAD: Shift + botão do meio orbita .nav-style-blender = Blender: botão do meio orbita, Shift desloca .nav-style-catia = CATIA: botão do meio + esquerdo orbita + .dynamic-ucs-on = SCU dinâmico: ativado + .dynamic-ucs-off = SCU dinâmico: desativado .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Touchpad: rolar move a vista, Ctrl+rolar ou pinçar aplica zoom .interface-scale = Escala da interface .zoom-factor = Fator de zoom diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index 771dfbcb9..0c48d9ed1 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -1558,6 +1558,8 @@ common = .nav-style-cad = CAD: Shift + средняя кнопка — вращение .nav-style-blender = Blender: средняя кнопка — вращение, Shift — сдвиг .nav-style-catia = CATIA: средняя + левая кнопка — вращение + .dynamic-ucs-on = Динамическая ПСК: вкл. + .dynamic-ucs-off = Динамическая ПСК: выкл. .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Тачпад: прокрутка панорамирует, Ctrl+прокрутка или щипок масштабирует .interface-scale = Масштаб интерфейса .zoom-factor = Коэффициент зумирования diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index 95ab5cff8..62ce2a837 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -1541,6 +1541,8 @@ common = .nav-style-cad = CAD: Shift + orta tuş döndürür .nav-style-blender = Blender: orta tuş döndürür, Shift kaydırır .nav-style-catia = CATIA: orta + sol tuş döndürür + .dynamic-ucs-on = Dinamik UCS: açık + .dynamic-ucs-off = Dinamik UCS: kapalı .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = Dokunmatik yüzey: kaydırma kaydırır, Ctrl+kaydırma veya sıkıştırma yakınlaştırır .interface-scale = Arayüz ölçeği .zoom-factor = Yakınlaştırma çarpanı diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index 0f3e81c96..0554f148a 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -1542,6 +1542,8 @@ common = .nav-style-cad = CAD:Shift + 中键旋转 .nav-style-blender = Blender:中键旋转,Shift 平移 .nav-style-catia = CATIA:中键 + 左键旋转 + .dynamic-ucs-on = 动态 UCS:开 + .dynamic-ucs-off = 动态 UCS:关 .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = 触控板:滚动平移,Ctrl+滚动或捏合缩放 .interface-scale = 界面缩放 .zoom-factor = 缩放系数 diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index 14a67c52d..d8510b264 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -1554,6 +1554,8 @@ common = .nav-style-cad = CAD:Shift + 中鍵旋轉 .nav-style-blender = Blender:中鍵旋轉,Shift 平移 .nav-style-catia = CATIA:中鍵 + 左鍵旋轉 + .dynamic-ucs-on = 動態 UCS:開 + .dynamic-ucs-off = 動態 UCS:關 .touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms = 觸控板:捲動平移,Ctrl+捲動或捏合縮放 .interface-scale = 介面縮放 .zoom-factor = 縮放係數 diff --git a/src/app/command_driver/utilities.rs b/src/app/command_driver/utilities.rs index 5be26f15d..a850e3283 100644 --- a/src/app/command_driver/utilities.rs +++ b/src/app/command_driver/utilities.rs @@ -624,6 +624,48 @@ impl OpenCADStudio { Some(key) } + /// Dynamic UCS: a command's first point picked on a planar solid face sets + /// the UCS to that face for the rest of the command. Returns the picked + /// point on the face. A snapped point (`snapped`) off the face's plane + /// belongs to other geometry, so it leaves the UCS alone. + pub(in crate::app) fn apply_dynamic_ucs( + &mut self, + snapped: Option, + ) -> Option { + let i = self.active_tab; + if !self.dynamic_ucs + || self.dynamic_ucs_restore.is_some() + || self.last_point.is_some() + || !self.tabs[i].editing_model_space() + || self.tabs[i] + .active_cmd + .as_ref() + .is_none_or(|command| command.name().starts_with("UCS")) + { + return None; + } + let cursor = self.tabs[i].scene.selection.borrow().input.last_move_pos?; + let (vw, vh) = self.tabs[i].scene.selection.borrow().view.vp_size; + let bounds = self.tabs[i].scene.active_model_tile_bounds(vw, vh); + let local = iced::Point::new(cursor.x - bounds.x, cursor.y - bounds.y); + let (ucs, pick) = self.tabs[i].scene.planar_face_ucs_at(bounds, local)?; + if let Some(point) = snapped { + let normal = glam::DVec3::new(ucs.x_axis.x, ucs.x_axis.y, ucs.x_axis.z) + .cross(glam::DVec3::new(ucs.y_axis.x, ucs.y_axis.y, ucs.y_axis.z)) + .normalize_or_zero(); + let off_plane = (point - pick).dot(normal).abs(); + if off_plane > 1.0e-6 * (1.0 + point.length().max(pick.length())) { + return None; + } + } + let saved = self.tabs[i].active_ucs.take(); + self.dynamic_ucs_restore = Some((self.tabs[i].id, saved)); + self.tabs[i].active_ucs = Some(ucs); + self.tabs[i].sync_ucs_to_scene(); + self.push_ucs_to_cmd(i); + Some(pick) + } + /// `feed_command`, also reporting whether the step actually took the input. /// Only a `Text` token can come back unclaimed (`on_text_input` returning /// `None`), which is what lets the caller read it as something else — a @@ -632,6 +674,9 @@ impl OpenCADStudio { &mut self, input: StepInput, ) -> (Task, bool) { + if matches!(input, StepInput::Point(_)) { + let _ = self.apply_dynamic_ucs(None); + } let gathering = self.report_selection_found(&input); // A command that takes associative dimensions only keeps just those: // the rest leave the selection and the count of what went is reported, diff --git a/src/app/commands/mod.rs b/src/app/commands/mod.rs index 1b98f6377..d2739f9e3 100644 --- a/src/app/commands/mod.rs +++ b/src/app/commands/mod.rs @@ -768,6 +768,7 @@ inventory::submit!(crate::command::CommandRegistration { "FILEDIA", "TRIMEXTENDMODE", "SELECTIONCYCLING", + "UCSDETECT", "SURFACEASSOCIATIVITY", "LAYOUTCREATEVIEWPORT", "FIELDEVAL", diff --git a/src/app/commands/styleprops.rs b/src/app/commands/styleprops.rs index 42d3d8d9c..f99c20694 100644 --- a/src/app/commands/styleprops.rs +++ b/src/app/commands/styleprops.rs @@ -1216,6 +1216,7 @@ impl OpenCADStudio { | "FILEDIA" | "TRIMEXTENDMODE" | "SELECTIONCYCLING" + | "UCSDETECT" | "SURFACEASSOCIATIVITY" | "UCSORTHO" | "UCSVIEW" @@ -1656,6 +1657,30 @@ impl OpenCADStudio { } return Some(self.finish_dispatch(cmd)); } + if name == "UCSDETECT" { + let current = i16::from(self.dynamic_ucs); + let prompt = format!("Enter new value for UCSDETECT <{current}>:"); + match value + .as_deref() + .map(|v| v.trim().parse::().ok().filter(|v| (0..=1).contains(v))) + { + Some(Some(mode)) => { + self.dynamic_ucs = mode == 1; + self.persist_settings_if_changed(); + } + Some(None) => { + self.command_line + .push_error(crate::t!("Requires 0 or 1 only.").as_ref()); + self.command_line.push_output(&prompt); + self.pending_setvar = Some(name.clone()); + } + None => { + self.command_line.push_output(&prompt); + self.pending_setvar = Some(name.clone()); + } + } + return Some(self.finish_dispatch(cmd)); + } if name == "SELECTIONCYCLING" { // 1 and 2 both turn cycling on; the candidate list // always shows. diff --git a/src/app/mod.rs b/src/app/mod.rs index 8837df446..4558ca2f6 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -655,6 +655,12 @@ pub(super) struct OpenCADStudio { /// CATIA navigation: the left button went down while the middle one was /// held, so the middle drag orbits until it is released. nav_left_with_middle: bool, + /// UCSDETECT: a command's first point on a planar solid face sets the + /// UCS to that face until the command ends. + dynamic_ucs: bool, + /// The UCS a dynamic UCS replaced, by tab id, restored when that tab's + /// command ends. + dynamic_ucs_restore: Option<(u64, Option)>, /// Scroll pans and Ctrl+scroll zooms (touchpads); see `scroll_intent`. touchpad_pan: bool, /// Multi-finger gestures on a touch screen. @@ -2663,6 +2669,8 @@ pub enum Message { /// Toggle reversing the mouse-wheel zoom direction (ZOOMWHEEL). ZoomWheelReversedChanged(bool), NavigationStyleChanged(crate::app::settings::NavigationStyle), + /// F6 / UCSDETECT: toggle the dynamic UCS. + ToggleDynamicUcs, TouchpadPanChanged(bool), /// Options: show the pull-down menus (MENUBAR). MenuBarChanged(bool), @@ -4640,6 +4648,8 @@ impl OpenCADStudio { zoom_wheel_reversed: false, navigation_style: Default::default(), nav_left_with_middle: false, + dynamic_ucs: true, + dynamic_ucs_restore: None, touchpad_pan: false, touch: Default::default(), touch_offset: None, diff --git a/src/app/settings.rs b/src/app/settings.rs index a5b625c18..2ffde4850 100644 --- a/src/app/settings.rs +++ b/src/app/settings.rs @@ -416,6 +416,9 @@ pub struct UserSettings { pub polar_increment_deg: f32, pub zoom_wheel_reversed: bool, pub navigation_style: NavigationStyle, + /// UCSDETECT: a command's first point on a planar solid face sets the + /// UCS to that face until the command ends. + pub dynamic_ucs: bool, /// Scrolling pans and Ctrl+scroll (a touchpad pinch) zooms, for a /// touchpad that reports two-finger drags as wheel scrolls. pub touchpad_pan: bool, @@ -920,6 +923,7 @@ impl Default for UserSettings { polar_increment_deg: 45.0, zoom_wheel_reversed: false, navigation_style: NavigationStyle::Cad, + dynamic_ucs: true, touchpad_pan: false, ui_scale_percent: 100, zoom_factor: 60, diff --git a/src/app/shortcuts.rs b/src/app/shortcuts.rs index a43b0286d..f67120ede 100644 --- a/src/app/shortcuts.rs +++ b/src/app/shortcuts.rs @@ -41,6 +41,7 @@ pub(super) fn default_bindings() -> BTreeMap { ("F3".to_string(), "TOGGLEOSNAP"), ("F4".to_string(), "TOGGLE3DOSNAP"), ("F5".to_string(), "ISOPLANE"), + ("F6".to_string(), "TOGGLEDUCS"), ("F7".to_string(), "GRID"), ("F8".to_string(), "ORTHO"), ("F9".to_string(), "SNAP"), @@ -185,6 +186,7 @@ pub(super) const INPUT_ACTIONS: &[&str] = &[ "COMMANDHISTORY", "TOGGLEOSNAP", "TOGGLE3DOSNAP", + "TOGGLEDUCS", "OTRACK", "DYNINPUT", "SELECTALL", @@ -343,6 +345,7 @@ impl OpenCADStudio { "COMMANDHISTORY" => Message::CommandHistoryToggle, "TOGGLEOSNAP" => Message::ToggleSnapEnabled, "TOGGLE3DOSNAP" => Message::ToggleSnap3dEnabled, + "TOGGLEDUCS" => Message::ToggleDynamicUcs, "OTRACK" => Message::ToggleOTrack, "DYNINPUT" => Message::ToggleDynInput, "SELECTALL" => Message::SelectAllShortcut, diff --git a/src/app/update/file.rs b/src/app/update/file.rs index 63171f8a3..f14bbd8a6 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -779,6 +779,7 @@ impl OpenCADStudio { polar_increment_deg: self.polar_increment_deg, zoom_wheel_reversed: self.zoom_wheel_reversed, navigation_style: self.navigation_style, + dynamic_ucs: self.dynamic_ucs, touchpad_pan: self.touchpad_pan, ui_scale_percent: self.ui_scale_percent, zoom_factor: self.zoom_factor, @@ -915,6 +916,7 @@ impl OpenCADStudio { self.polar_increment_deg = s.polar_increment_deg; self.zoom_wheel_reversed = s.zoom_wheel_reversed; self.navigation_style = s.navigation_style; + self.dynamic_ucs = s.dynamic_ucs; self.touchpad_pan = s.touchpad_pan; self.ui_scale_percent = crate::app::settings::clamp_ui_scale(s.ui_scale_percent); self.zoom_factor = crate::app::settings::clamp_zoom_factor(s.zoom_factor); diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 8c304ff27..263bba5e6 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -374,6 +374,7 @@ impl OpenCADStudio { // document's selection. let before = self.tabs.get(self.active_tab).map(|tab| tab.id); let task = self.update_message(msg); + self.restore_dynamic_ucs_after_command(); if self.tabs.get(self.active_tab).map(|tab| tab.id) != before { self.sync_underlay_tab(); } @@ -396,6 +397,25 @@ impl OpenCADStudio { task } + /// A dynamic UCS lasts for the command that set it: once that tab's + /// command has ended, the UCS it replaced comes back. + fn restore_dynamic_ucs_after_command(&mut self) { + let Some((tab_id, _)) = self.dynamic_ucs_restore else { + return; + }; + let Some(i) = self.tabs.iter().position(|tab| tab.id == tab_id) else { + self.dynamic_ucs_restore = None; + return; + }; + if self.tabs[i].active_cmd.is_some() { + return; + } + if let Some((_, saved)) = self.dynamic_ucs_restore.take() { + self.tabs[i].active_ucs = saved; + self.tabs[i].sync_ucs_to_scene(); + } + } + /// The Frames list on the ribbon shows the active drawing's frame state /// (FRAME), however it was changed: the list, a command, undo or another /// drawing. @@ -9245,6 +9265,18 @@ impl OpenCADStudio { Task::none() } + Message::ToggleDynamicUcs => { + self.dynamic_ucs = !self.dynamic_ucs; + self.command_line.push_output(if self.dynamic_ucs { + crate::t!("Dynamic UCS: on") + } else { + crate::t!("Dynamic UCS: off") + } + .as_ref()); + self.persist_settings_if_changed(); + Task::none() + } + Message::NavigationStyleChanged(style) => { self.navigation_style = style; self.persist_settings_if_changed(); diff --git a/src/app/update/viewport.rs b/src/app/update/viewport.rs index 107bdb7c4..e343f07a3 100644 --- a/src/app/update/viewport.rs +++ b/src/app/update/viewport.rs @@ -4325,6 +4325,7 @@ impl OpenCADStudio { }; let snap_taken = self.tabs[i].snap_result.take(); + let snapped = snap_taken.is_some(); let tangent_obj_at_click = snap_taken.and_then(|s| s.tangent_obj); let world_pt = { @@ -5019,6 +5020,11 @@ impl OpenCADStudio { self.finish_command_click(i); return Task::none(); } + // An unsnapped first point on a solid face lands on the face. + let world_pt = match self.apply_dynamic_ucs(snapped.then_some(world_pt)) { + Some(on_face) if !snapped => on_face, + _ => world_pt, + }; self.last_point = Some(world_pt); // The one-shot snap override is spent by this pick — // restore the running osnap configuration (#337). diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index b7d956730..00ff2ac57 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -5074,6 +5074,8 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static "CAD: Shift + middle button orbits" => Some(("common", "nav-style-cad")), "Blender: middle button orbits, Shift pans" => Some(("common", "nav-style-blender")), "CATIA: middle + left button orbits" => Some(("common", "nav-style-catia")), + "Dynamic UCS: on" => Some(("common", "dynamic-ucs-on")), + "Dynamic UCS: off" => Some(("common", "dynamic-ucs-off")), "Touchpad: scroll pans, Ctrl+scroll or pinch zooms" => Some(("common", "touchpad-scroll-pans-ctrl-scroll-or-pinch-zooms")), "Interface scale" => Some(("common", "interface-scale")), "Zoom factor" => Some(("common", "zoom-factor")), diff --git a/src/scene/mod.rs b/src/scene/mod.rs index 074b35015..380663425 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -11363,6 +11363,25 @@ impl Scene { ) } + /// The UCS of the planar solid face under `local` (relative to `bounds`), + /// Z along the face normal, and the picked point on the face. + pub fn planar_face_ucs_at( + &mut self, + bounds: iced::Rectangle, + local: iced::Point, + ) -> Option<(codec::tables::Ucs, glam::DVec3)> { + let camera = self.camera.borrow(); + let view_rot = camera.view_proj_rte(bounds); + let eye = camera.eye(); + drop(camera); + let (handle, pick) = self.solid_click_hit_point(local, view_rot, eye, bounds)?; + self.restore_solid_models(&[handle]); + let body = self.solid_models.get(&handle)?; + let face = crate::scene::model::solid_model::nearest_planar_face(body, pick.to_array())?; + crate::scene::model::solid_model::planar_face_ucs(body, face, pick.to_array()) + .map(|ucs| (ucs, pick)) + } + /// The nearest solid or mesh surface under `local` (relative to `bounds`). pub fn surface_pivot_at( &self,