diff --git a/locales/ar-SA/opencadstudio.ftl b/locales/ar-SA/opencadstudio.ftl index 8f824e0c3..93a36a4d2 100644 --- a/locales/ar-SA/opencadstudio.ftl +++ b/locales/ar-SA/opencadstudio.ftl @@ -4011,6 +4011,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = إنشاء .boolean = عمليات منطقية diff --git a/locales/bg-BG/opencadstudio.ftl b/locales/bg-BG/opencadstudio.ftl index 656076e43..33c312e7b 100644 --- a/locales/bg-BG/opencadstudio.ftl +++ b/locales/bg-BG/opencadstudio.ftl @@ -3998,6 +3998,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Създаване .boolean = Булеви операции diff --git a/locales/cs-CZ/opencadstudio.ftl b/locales/cs-CZ/opencadstudio.ftl index 817a1b1d1..9549ccac5 100644 --- a/locales/cs-CZ/opencadstudio.ftl +++ b/locales/cs-CZ/opencadstudio.ftl @@ -3996,6 +3996,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Vytvořit .boolean = Booleovské operace diff --git a/locales/de-DE/opencadstudio.ftl b/locales/de-DE/opencadstudio.ftl index 10434f924..423fb8678 100644 --- a/locales/de-DE/opencadstudio.ftl +++ b/locales/de-DE/opencadstudio.ftl @@ -3997,6 +3997,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Erstellen .boolean = Boolesche Operationen diff --git a/locales/el-GR/opencadstudio.ftl b/locales/el-GR/opencadstudio.ftl index 8058b678e..087579b77 100644 --- a/locales/el-GR/opencadstudio.ftl +++ b/locales/el-GR/opencadstudio.ftl @@ -3999,6 +3999,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Δημιουργία .boolean = Δυαδική πράξη diff --git a/locales/en-US/opencadstudio.ftl b/locales/en-US/opencadstudio.ftl index 21c6dd4df..7f99698b7 100644 --- a/locales/en-US/opencadstudio.ftl +++ b/locales/en-US/opencadstudio.ftl @@ -4000,6 +4000,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Create .boolean = Boolean diff --git a/locales/es-ES/opencadstudio.ftl b/locales/es-ES/opencadstudio.ftl index de8a0737a..60dffb911 100644 --- a/locales/es-ES/opencadstudio.ftl +++ b/locales/es-ES/opencadstudio.ftl @@ -3999,6 +3999,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Crear .boolean = Booleanas diff --git a/locales/fi-FI/opencadstudio.ftl b/locales/fi-FI/opencadstudio.ftl index 090bd5e2f..6279fea91 100644 --- a/locales/fi-FI/opencadstudio.ftl +++ b/locales/fi-FI/opencadstudio.ftl @@ -3998,6 +3998,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Luo .boolean = Boolen operaatiot diff --git a/locales/fr-FR/opencadstudio.ftl b/locales/fr-FR/opencadstudio.ftl index 9e6f9311e..6347339d4 100644 --- a/locales/fr-FR/opencadstudio.ftl +++ b/locales/fr-FR/opencadstudio.ftl @@ -3999,6 +3999,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Créer .boolean = Opérations booléennes diff --git a/locales/hi-IN/opencadstudio.ftl b/locales/hi-IN/opencadstudio.ftl index c80494f30..f1384b42b 100644 --- a/locales/hi-IN/opencadstudio.ftl +++ b/locales/hi-IN/opencadstudio.ftl @@ -3987,6 +3987,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = बनाएँ .boolean = बूलियन संक्रियाएँ diff --git a/locales/hu-HU/opencadstudio.ftl b/locales/hu-HU/opencadstudio.ftl index 7c37e76bf..cc45f9d92 100644 --- a/locales/hu-HU/opencadstudio.ftl +++ b/locales/hu-HU/opencadstudio.ftl @@ -3998,6 +3998,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Létrehozás .boolean = Logikai műveletek diff --git a/locales/it-IT/opencadstudio.ftl b/locales/it-IT/opencadstudio.ftl index 954d775cd..ebb736379 100644 --- a/locales/it-IT/opencadstudio.ftl +++ b/locales/it-IT/opencadstudio.ftl @@ -3998,6 +3998,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Crea .boolean = Operazioni booleane diff --git a/locales/ja-JP/opencadstudio.ftl b/locales/ja-JP/opencadstudio.ftl index 88caf86eb..dbb5e7649 100644 --- a/locales/ja-JP/opencadstudio.ftl +++ b/locales/ja-JP/opencadstudio.ftl @@ -3987,6 +3987,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = 作成 .boolean = ブール演算 diff --git a/locales/ko-KR/opencadstudio.ftl b/locales/ko-KR/opencadstudio.ftl index 156e0146b..7d1e6615b 100644 --- a/locales/ko-KR/opencadstudio.ftl +++ b/locales/ko-KR/opencadstudio.ftl @@ -3998,6 +3998,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = 생성 .boolean = 불리언 연산 diff --git a/locales/nl-NL/opencadstudio.ftl b/locales/nl-NL/opencadstudio.ftl index 08a40f997..51e16f52e 100644 --- a/locales/nl-NL/opencadstudio.ftl +++ b/locales/nl-NL/opencadstudio.ftl @@ -3997,6 +3997,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Maken .boolean = Booleaanse bewerkingen diff --git a/locales/pl-PL/opencadstudio.ftl b/locales/pl-PL/opencadstudio.ftl index 611ee84d6..d990b8e06 100644 --- a/locales/pl-PL/opencadstudio.ftl +++ b/locales/pl-PL/opencadstudio.ftl @@ -3998,6 +3998,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Utwórz .boolean = Operacje boolowskie diff --git a/locales/pt-BR/opencadstudio.ftl b/locales/pt-BR/opencadstudio.ftl index b823c8f5d..36f801710 100644 --- a/locales/pt-BR/opencadstudio.ftl +++ b/locales/pt-BR/opencadstudio.ftl @@ -3999,6 +3999,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Criar .boolean = Operações booleanas diff --git a/locales/ru-RU/opencadstudio.ftl b/locales/ru-RU/opencadstudio.ftl index d49dfa068..bc0715a63 100644 --- a/locales/ru-RU/opencadstudio.ftl +++ b/locales/ru-RU/opencadstudio.ftl @@ -4000,6 +4000,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = Создание .boolean = Булевы операции diff --git a/locales/tr-TR/opencadstudio.ftl b/locales/tr-TR/opencadstudio.ftl index 4d018e78c..0c73a6649 100644 --- a/locales/tr-TR/opencadstudio.ftl +++ b/locales/tr-TR/opencadstudio.ftl @@ -3959,6 +3959,27 @@ insert = .pc-search = Ara .pc-collapse-all = Tümünü daralt .pc-expand-all = Tümünü genişlet + .pcm-scheme-name = Şema adı + .pcs-title = Nokta Bulutundan Kesit Çizgileri Çıkar + .pcs-extract = Çıkar + .pcs-entire = Tüm kesit + .pcs-perimeter = Yalnız çevre + .pcs-max-points = En fazla işlenecek nokta + .pcs-faster = Daha hızlı + .pcs-accurate = Daha doğru + .pcs-time = Tahmini süre: __ocs_fmt_0__ dk + .pcs-output = Çıktı geometrisi + .pcs-polylines = 2B Çoklu çizgiler + .pcs-width = Çoklu çizgi genişliği + .pcs-tolerances = Çıkarma toleransları + .pcs-min-length = En kısa çizgi uzunluğu + .pcs-connect = Çizgi birleştirme toleransı + .pcs-angle = Doğrusal açı toleransı + .pcs-preview = Sonucu önizle + .pcs-use-current = Geçerli katmanı kullan + .pcs-positive = Pozitif bir sayı gerekir. + .pcs-positive-int = Pozitif bir tamsayı gerekir. + .pcs-help = Canlı kesitin korunan tarafındaki noktaları çizgilerle izler. model = .create = Oluştur .boolean = Boole işlemleri diff --git a/locales/zh-CN/opencadstudio.ftl b/locales/zh-CN/opencadstudio.ftl index a0021231e..9b004a4b0 100644 --- a/locales/zh-CN/opencadstudio.ftl +++ b/locales/zh-CN/opencadstudio.ftl @@ -3982,6 +3982,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = 创建 .boolean = 布尔运算 diff --git a/locales/zh-TW/opencadstudio.ftl b/locales/zh-TW/opencadstudio.ftl index 39de64ead..b263be935 100644 --- a/locales/zh-TW/opencadstudio.ftl +++ b/locales/zh-TW/opencadstudio.ftl @@ -3994,6 +3994,27 @@ insert = .pc-search = Search .pc-collapse-all = Collapse all .pc-expand-all = Expand all + .pcm-scheme-name = Scheme name + .pcs-title = Extract Section Lines from Point Cloud + .pcs-extract = Extract + .pcs-entire = Entire cross section + .pcs-perimeter = Perimeter only + .pcs-max-points = Maximum points to process + .pcs-faster = Faster + .pcs-accurate = More accurate + .pcs-time = Estimated time: __ocs_fmt_0__ min + .pcs-output = Output geometry + .pcs-polylines = 2D Polylines + .pcs-width = Polyline width + .pcs-tolerances = Extraction tolerances + .pcs-min-length = Minimum line length + .pcs-connect = Connect lines tolerance + .pcs-angle = Collinear angle tolerance + .pcs-preview = Preview result + .pcs-use-current = Use Current + .pcs-positive = Requires a positive number. + .pcs-positive-int = Requires a positive integer. + .pcs-help = Traces the points on the kept side of a live section as lines. model = .create = 建立 .boolean = 布林運算 diff --git a/src/app/commands/pc_extract.rs b/src/app/commands/pc_extract.rs index 3dbfe5a14..5c45f4771 100644 --- a/src/app/commands/pc_extract.rs +++ b/src/app/commands/pc_extract.rs @@ -3,6 +3,7 @@ //! and its section objects when they start. use super::*; +use crate::ui::window::pdf_dialogs::PdfDialogMsg; use codec::entities::ExtendedEntityData; use glam::DVec3; @@ -80,6 +81,10 @@ impl OpenCADStudio { self.extraction_clouds(i), self.extraction_sections(i), )), + "_PCSECTIONDLG" => { + self.open_pc_section_dialog(i); + return Some(self.finish_dispatch(cmd)); + } _ => return None, }; self.command_line.push_info(&command.prompt()); @@ -87,3 +92,108 @@ impl OpenCADStudio { Some(self.finish_dispatch(cmd)) } } + +impl OpenCADStudio { + /// PCEXTRACTSECTION's settings dialog, filled from the session settings. + fn open_pc_section_dialog(&mut self, i: usize) { + use crate::modules::insert::pc_extract::{has_job, settings}; + use crate::ui::window::pdf_dialogs::{LineColor, PcSectionState}; + if !has_job() { + return; + } + let s = settings(); + let current = crate::t!("Use Current").into_owned(); + let mut layers = vec![current.clone()]; + let mut names: Vec = self.tabs[i].scene.document.layers.iter().map(|l| l.name.clone()).collect(); + names.sort_by_key(|n| n.to_lowercase()); + layers.extend(names); + let short = |v: f64| { + let t = format!("{v:.4}"); + t.trim_end_matches('0').trim_end_matches('.').to_string() + }; + self.pc_section = Some(PcSectionState { + perimeter: s.perimeter, + max_points: s.max_points.to_string(), + layers, + layer: s.layer.clone().unwrap_or(current), + color: LineColor(s.color), + polylines: s.polylines, + width: short(s.width), + min_length: short(s.min_length), + connect: short(s.connect), + angle: short(s.angle), + preview: s.preview, + }); + self.active_modal = Some(crate::app::ModalKind::PcSection); + } + + pub(in crate::app) fn update_pc_section(&mut self, message: PdfDialogMsg) -> Task { + use crate::modules::insert::pc_extract::{set_settings, settings, SectionCommand, SectionDistanceCommand}; + use crate::command::CadCommand; + let i = self.active_tab; + let Some(state) = self.pc_section.as_mut() else { + return Task::none(); + }; + match message { + PdfDialogMsg::SecPerimeter(on) => state.perimeter = on, + PdfDialogMsg::SecMaxPoints(v) => state.max_points = v, + PdfDialogMsg::SecLayer(v) => state.layer = v, + PdfDialogMsg::SecColor(c) => state.color = c, + PdfDialogMsg::SecPolylines(on) => state.polylines = on, + PdfDialogMsg::SecWidth(v) => state.width = v, + PdfDialogMsg::SecMinLength(v) => state.min_length = v, + PdfDialogMsg::SecConnect(v) => state.connect = v, + PdfDialogMsg::SecAngle(v) => state.angle = v, + PdfDialogMsg::SecPreview(on) => state.preview = on, + // Measure on screen, then back to the dialog (the extraction waits). + PdfDialogMsg::SecPick(connect) => { + self.pc_section = None; + self.active_modal = None; + let command = SectionDistanceCommand::new(connect); + self.command_line.push_info(&command.prompt()); + self.tabs[i].active_cmd = Some(Box::new(command)); + } + PdfDialogMsg::SecCreate => { + let number = |t: &str| crate::entities::common::parse_f64(t.trim()); + let (min_length, connect, width) = (number(&state.min_length), number(&state.connect), number(&state.width)); + let (Some(min_length), Some(connect)) = (min_length.filter(|v| *v > 0.0), connect.filter(|v| *v > 0.0)) else { + self.command_line.push_error(crate::t!("Requires a positive number.").as_ref()); + return Task::none(); + }; + let Some(angle) = state.angle.trim().parse::().ok().filter(|v| (0..=10).contains(v)) else { + self.command_line + .push_error("Colinear angle tolerance only accepts integer from 0 to 10."); + return Task::none(); + }; + let Some(max_points) = state.max_points.trim().parse::().ok().filter(|v| *v > 0) else { + self.command_line.push_error(crate::t!("Requires a positive integer.").as_ref()); + return Task::none(); + }; + let current = crate::t!("Use Current").into_owned(); + let mut s = settings(); + s.perimeter = state.perimeter; + s.max_points = max_points; + s.layer = (state.layer != current).then(|| state.layer.clone()); + s.color = state.color.0; + s.polylines = state.polylines; + s.width = width.filter(|v| *v >= 0.0).unwrap_or(0.0); + s.min_length = min_length; + s.connect = connect; + s.angle = angle as f64; + s.preview = state.preview; + set_settings(s); + self.pc_section = None; + self.active_modal = None; + let Some(mut command) = SectionCommand::resume() else { + return Task::none(); + }; + let result = command.run(); + self.command_line.push_info(&command.prompt()); + self.tabs[i].active_cmd = Some(Box::new(command)); + return self.apply_cmd_result(result); + } + _ => {} + } + Task::none() + } +} diff --git a/src/app/commands/pdf_dialogs.rs b/src/app/commands/pdf_dialogs.rs index 47435b4aa..187de6315 100644 --- a/src/app/commands/pdf_dialogs.rs +++ b/src/app/commands/pdf_dialogs.rs @@ -378,6 +378,7 @@ impl OpenCADStudio { } "attach" => crate::t!("Attaches a PDF file as an underlay."), "pointcloud" => crate::t!("Attaches a point cloud scan or project."), + "pcsection" => crate::t!("Traces the points on the kept side of a live section as lines."), "pointcloudcolormap" => { crate::t!("Sets the color schemes and ranges a point cloud is colored by intensity or elevation.") } @@ -503,6 +504,18 @@ impl OpenCADStudio { | PdfDialogMsg::MapCurrent(_) | PdfDialogMsg::MapApply | PdfDialogMsg::MapOk) => return self.update_point_cloud_color_map(message), + message @ (PdfDialogMsg::SecPerimeter(_) + | PdfDialogMsg::SecMaxPoints(_) + | PdfDialogMsg::SecLayer(_) + | PdfDialogMsg::SecColor(_) + | PdfDialogMsg::SecPolylines(_) + | PdfDialogMsg::SecWidth(_) + | PdfDialogMsg::SecMinLength(_) + | PdfDialogMsg::SecConnect(_) + | PdfDialogMsg::SecAngle(_) + | PdfDialogMsg::SecPick(_) + | PdfDialogMsg::SecPreview(_) + | PdfDialogMsg::SecCreate) => return self.update_pc_section(message), PdfDialogMsg::CloudPathType(choice) => { let stored = self.point_cloud_attach.as_ref().map(|s| self.pdf_stored_path(&s.path, choice.0)); if let (Some(s), Some(stored)) = (self.point_cloud_attach.as_mut(), stored) { diff --git a/src/app/control/actions.rs b/src/app/control/actions.rs index 78401823b..3f1b75b8d 100644 --- a/src/app/control/actions.rs +++ b/src/app/control/actions.rs @@ -75,6 +75,7 @@ pub(super) const NAMES: &[&str] = &[ "pc_manager", "pdf_page_select", "pc_colormap", + "pc_section", "ribbon_tab", "ribbon_dropdown", "dialog_ok", @@ -721,6 +722,24 @@ impl OpenCADStudio { _ => return Err(failure("invalid_value", "Unknown color map edit")), }) } + // Section extraction dialog: "min=0.01", "connect=0.02", "angle=5", + // "points=18000", "lines=1", "perimeter=1", "preview=0", "width=0". + "pc_section" => { + use crate::ui::window::pdf_dialogs::PdfDialogMsg as M; + let value = string(req, "value")?; + let (key, arg) = value.split_once('=').unwrap_or((value, "")); + Message::PdfDialog(match key { + "min" => M::SecMinLength(arg.into()), + "connect" => M::SecConnect(arg.into()), + "angle" => M::SecAngle(arg.into()), + "points" => M::SecMaxPoints(arg.into()), + "width" => M::SecWidth(arg.into()), + "lines" => M::SecPolylines(arg == "0"), + "perimeter" => M::SecPerimeter(arg != "0"), + "preview" => M::SecPreview(arg != "0"), + _ => return Err(failure("invalid_value", "Unknown section setting")), + }) + } // Point Cloud Manager: flip a row's switch, ":" with // row cloud, unassigned, scans or scan:. "pc_manager_toggle" => { @@ -776,6 +795,7 @@ impl OpenCADStudio { Some(crate::app::ModalKind::PdfAttach) => PdfDialogMsg::AttachOk, Some(crate::app::ModalKind::PointCloudAttach) => PdfDialogMsg::CloudOk, Some(crate::app::ModalKind::PointCloudColorMap) => PdfDialogMsg::MapOk, + Some(crate::app::ModalKind::PcSection) => PdfDialogMsg::SecCreate, Some(crate::app::ModalKind::UnderlayLayers) => PdfDialogMsg::LayersOk, Some(crate::app::ModalKind::PdfImportSettings) => PdfDialogMsg::SettingsOk, Some(crate::app::ModalKind::PdfImportFile) => PdfDialogMsg::ImportOk, diff --git a/src/app/mod.rs b/src/app/mod.rs index 231d83b98..c79ed42d0 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -499,6 +499,7 @@ pub(super) struct OpenCADStudio { pdf_attach: Option, point_cloud_attach: Option, point_cloud_color_map: Option, + pc_section: Option, underlay_layers: Option, pdf_import_settings: Option, pdf_import_file: Option, @@ -1907,6 +1908,7 @@ pub enum ModalKind { PdfAttach, PointCloudAttach, PointCloudColorMap, + PcSection, UnderlayLayers, PdfImportSettings, PdfImportFile, @@ -4041,6 +4043,7 @@ impl OpenCADStudio { pdf_attach: None, point_cloud_attach: None, point_cloud_color_map: None, + pc_section: None, underlay_layers: None, pdf_import_settings: None, pdf_import_file: None, diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index 355f65358..3a89500a0 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -8485,6 +8485,11 @@ impl OpenCADStudio { } Message::CloseModal => { + // Cancelling the section settings drops the waiting extraction. + if self.active_modal == Some(super::ModalKind::PcSection) { + crate::modules::insert::pc_extract::drop_job(); + self.pc_section = None; + } if self.active_modal == Some(super::ModalKind::RecoveryPrompt) { return self.update(Message::RecoveryDecline); } diff --git a/src/app/view/modal.rs b/src/app/view/modal.rs index 6eec7b710..07ebdc8da 100644 --- a/src/app/view/modal.rs +++ b/src/app/view/modal.rs @@ -31,6 +31,7 @@ impl OpenCADStudio { }, Some(K::PointCloudAttach) => crate::t!("Attach Point Cloud").into_owned(), Some(K::PointCloudColorMap) => crate::t!("Point Cloud Color Map").into_owned(), + Some(K::PcSection) => crate::t!("Extract Section Lines from Point Cloud").into_owned(), Some(K::UnderlayLayers) => crate::t!("Underlay Layers").into_owned(), Some(K::PdfImportSettings) => crate::t!("PDF Import Settings").into_owned(), Some(K::PdfImportFile) => crate::t!("Import PDF").into_owned(), @@ -536,6 +537,10 @@ impl OpenCADStudio { crate::ui::window::pdf_dialogs::view_point_cloud_color_map(state, flow) }) } + super::super::ModalKind::PcSection => { + let state = self.pc_section.as_ref()?; + sized_flow(ex, 760, 470, |flow| crate::ui::window::pdf_dialogs::view_pc_section(state, flow)) + } super::super::ModalKind::UnderlayLayers => { let state = self.underlay_layers.as_ref()?; sized_flow(ex, 460, 520, |flow| { diff --git a/src/locale_catalog.rs b/src/locale_catalog.rs index 88712300f..8a1e880cc 100644 --- a/src/locale_catalog.rs +++ b/src/locale_catalog.rs @@ -143,6 +143,26 @@ pub(super) fn message_attribute(source: &str) -> Option<(&'static str, &'static "Collapse all" => Some(("insert", "pc-collapse-all")), "Expand all" => Some(("insert", "pc-expand-all")), "Scheme name" => Some(("insert", "pcm-scheme-name")), + "Extract Section Lines from Point Cloud" => Some(("insert", "pcs-title")), + "Extract" => Some(("insert", "pcs-extract")), + "Entire cross section" => Some(("insert", "pcs-entire")), + "Perimeter only" => Some(("insert", "pcs-perimeter")), + "Maximum points to process" => Some(("insert", "pcs-max-points")), + "Faster" => Some(("insert", "pcs-faster")), + "More accurate" => Some(("insert", "pcs-accurate")), + "Estimated time: {count} min" => Some(("insert", "pcs-time")), + "Output geometry" => Some(("insert", "pcs-output")), + "2D Polylines" => Some(("insert", "pcs-polylines")), + "Polyline width" => Some(("insert", "pcs-width")), + "Extraction tolerances" => Some(("insert", "pcs-tolerances")), + "Minimum line length" => Some(("insert", "pcs-min-length")), + "Connect lines tolerance" => Some(("insert", "pcs-connect")), + "Collinear angle tolerance" => Some(("insert", "pcs-angle")), + "Preview result" => Some(("insert", "pcs-preview")), + "Use Current" => Some(("insert", "pcs-use-current")), + "Requires a positive number." => Some(("insert", "pcs-positive")), + "Requires a positive integer." => Some(("insert", "pcs-positive-int")), + "Traces the points on the kept side of a live section as lines." => Some(("insert", "pcs-help")), "Stylization" => Some(("properties", "stylization")), "Color scheme" => Some(("properties", "color-scheme")), "Scan Colors" => Some(("properties", "scan-colors")), diff --git a/src/modules/insert/pc_extract.rs b/src/modules/insert/pc_extract.rs index d11f0411c..a355f3766 100644 --- a/src/modules/insert/pc_extract.rs +++ b/src/modules/insert/pc_extract.rs @@ -496,31 +496,61 @@ pub struct Section { /// The extraction settings (the reference's dialog defaults), kept for the /// session. -#[derive(Clone, Copy)] -struct Settings { - perimeter: bool, - max_points: usize, - polylines: bool, - width: f64, - min_length: f64, - connect: f64, - angle: f64, +#[derive(Clone, Debug, PartialEq)] +pub struct Settings { + pub perimeter: bool, + pub max_points: usize, + /// The layer the lines go on; `None` is the current layer. + pub layer: Option, + /// The lines' colour (ACI; 256 ByLayer, 0 ByBlock). + pub color: i16, + pub polylines: bool, + pub width: f64, + pub min_length: f64, + pub connect: f64, + pub angle: f64, + /// Show the result and ask to accept it (else create it at once). + pub preview: bool, } const DEFAULTS: Settings = Settings { perimeter: false, max_points: 18_000, + layer: None, + color: 3, polylines: true, width: 0.0, min_length: 150.0, connect: 300.0, angle: 5.0, + preview: true, }; static SETTINGS: Mutex = Mutex::new(DEFAULTS); -fn settings() -> Settings { - SETTINGS.lock().map(|s| *s).unwrap_or(DEFAULTS) +pub fn settings() -> Settings { + SETTINGS.lock().map(|s| s.clone()).unwrap_or(DEFAULTS) +} + +pub fn set_settings(settings: Settings) { + if let Ok(mut stored) = SETTINGS.lock() { + *stored = settings; + } +} + +/// The cloud and section a PCEXTRACTSECTION is extracting from while its +/// settings dialog is open. +static JOB: Mutex> = Mutex::new(None); + +/// Whether an extraction waits for its settings dialog. +pub fn has_job() -> bool { + JOB.lock().is_ok_and(|job| job.is_some()) +} + +pub fn drop_job() { + if let Ok(mut job) = JOB.lock() { + *job = None; + } } const TOO_FEW: &str = "Too few points to process. No geometry extracted from point cloud."; @@ -734,7 +764,11 @@ impl SectionCommand { .into_iter() .map(|p| plane.to_local(p).truncate()) .collect(); - let color = Color::from_index(3); + let color = match s.color { + 256 => Color::ByLayer, + 0 => Color::ByBlock, + index => Color::from_index(index), + }; let mut out = Vec::new(); for chain in trace(&flat, &s) { if s.polylines { @@ -744,6 +778,9 @@ impl SectionCommand { ..Default::default() }; pline.common.color = color.clone(); + if let Some(layer) = &s.layer { + pline.common.layer = layer.clone(); + } out.push(plane.place_entity(EntityType::LwPolyline(pline))); } else { for w in chain.windows(2) { @@ -752,6 +789,9 @@ impl SectionCommand { vector(plane.to_world(w[1].extend(0.0))), ); line.common.color = color.clone(); + if let Some(layer) = &s.layer { + line.common.layer = layer.clone(); + } out.push(EntityType::Line(line)); } } @@ -759,11 +799,22 @@ impl SectionCommand { Ok(out) } + /// PCEXTRACTSECTION after its settings dialog: the waiting cloud and + /// section, extracted with the settings. + pub fn resume() -> Option { + let (cloud, section) = JOB.lock().ok()?.take()?; + let mut command = Self::new(true, Clouds::default(), Vec::new()); + command.cloud = Some(cloud); + command.section = Some(section); + command.step = SectionStep::Accept; + Some(command) + } + /// Extracts; asks to accept when previewing, else creates. - fn run(&mut self) -> CmdResult { + pub fn run(&mut self) -> CmdResult { match self.extract() { Err(message) => CmdResult::CancelWithMessage(message.to_string()), - Ok(entities) if !self.ask => { + Ok(entities) if !self.ask || !settings().preview => { if entities.is_empty() { CmdResult::Cancel } else { CmdResult::CommitEntitiesAndExit(entities) } } Ok(entities) => { @@ -862,21 +913,68 @@ impl SectionCommand { "2" | "2D" | "P" | "POLYLINES" | "2D POLYLINES" => s.polylines = true, _ => return CmdResult::ReportError("Invalid option keyword.".to_string()), } - if let Ok(mut stored) = SETTINGS.lock() { - *stored = s; - } + set_settings(s); return self.run(); } _ => return CmdResult::NeedPoint, }; - if let Ok(mut stored) = SETTINGS.lock() { - *stored = s; - } + set_settings(s); self.step = next; CmdResult::NeedPoint } } +/// The dialog's pick buttons: a distance measured by two points on screen, +/// then the dialog again. +pub struct SectionDistanceCommand { + /// Connect lines tolerance (else minimum line length). + connect: bool, + first: Option, +} + +impl SectionDistanceCommand { + pub fn new(connect: bool) -> Self { + Self { connect, first: None } + } +} + +impl CadCommand for SectionDistanceCommand { + fn name(&self) -> &'static str { + "PCEXTRACTSECTION" + } + + fn prompt(&self) -> String { + if self.first.is_none() { "Specify first point:" } else { "Specify second point:" }.to_string() + } + + fn on_point(&mut self, pt: DVec3) -> CmdResult { + let Some(first) = self.first else { + self.first = Some(pt); + return CmdResult::NeedPoint; + }; + let mut s = settings(); + let distance = first.distance(pt); + if distance > 0.0 { + if self.connect { + s.connect = distance; + } else { + s.min_length = distance; + } + set_settings(s); + } + CmdResult::Dispatch("_PCSECTIONDLG".to_string()) + } + + fn on_enter(&mut self) -> CmdResult { + CmdResult::Dispatch("_PCSECTIONDLG".to_string()) + } + + fn on_mouse_move(&mut self, pt: DVec3) -> Option { + let first = self.first?; + Some(WireModel::solid_f64("pc_section_distance".into(), vec![first.to_array(), pt.to_array()], [1.0, 1.0, 1.0, 1.0], false)) + } +} + /// The OCS axes of an entity normal (arbitrary axis algorithm) as columns. fn ocs(normal: Vector3) -> DMat3 { let n = DVec3::new(normal.x, normal.y, normal.z).normalize_or(DVec3::Z); @@ -950,6 +1048,13 @@ impl CadCommand for SectionCommand { let Some(cloud) = self.clouds.of(handle) else { return CmdResult::CancelWithMessage("The point cloud is not loaded.".to_string()); }; + // PCEXTRACTSECTION asks its settings in the dialog first. + if self.ask { + if let Ok(mut job) = JOB.lock() { + *job = Some((cloud, section)); + } + return CmdResult::Dispatch("_PCSECTIONDLG".to_string()); + } self.cloud = Some(cloud); self.section = Some(section); self.run() @@ -967,6 +1072,13 @@ impl CadCommand for SectionCommand { let entities = std::mem::take(&mut self.result); if entities.is_empty() { CmdResult::Cancel } else { CmdResult::CommitEntitiesAndExit(entities) } } + // Back to the settings dialog with the same cloud and section. + "" | "S" | "SETTINGS" if self.ask => { + if let (Some(cloud), Some(section), Ok(mut job)) = (self.cloud.take(), self.section, JOB.lock()) { + *job = Some((cloud, section)); + } + CmdResult::Dispatch("_PCSECTIONDLG".to_string()) + } "" | "S" | "SETTINGS" => { self.step = SectionStep::Extract; CmdResult::NeedPoint diff --git a/src/ui/window/pdf_dialogs.rs b/src/ui/window/pdf_dialogs.rs index d70fa4fee..b860bb94e 100644 --- a/src/ui/window/pdf_dialogs.rs +++ b/src/ui/window/pdf_dialogs.rs @@ -70,6 +70,20 @@ pub enum PdfDialogMsg { MapCurrent(bool), MapApply, MapOk, + // Extract Section Lines from Point Cloud + SecPerimeter(bool), + SecMaxPoints(String), + SecLayer(String), + SecColor(LineColor), + SecPolylines(bool), + SecWidth(String), + SecMinLength(String), + SecConnect(String), + SecAngle(String), + /// Measure the connect tolerance (else the minimum length) on screen. + SecPick(bool), + SecPreview(bool), + SecCreate, // Underlay Layers LayersUnderlay(String), LayersSearch(String), @@ -1488,3 +1502,171 @@ pub fn view_point_cloud_color_map<'a>( .align_y(iced::Center); column![tabs, body, footer].spacing(10).padding([10, 12]).width(sizing.width).into() } + +// ── Extract Section Lines from Point Cloud ───────────────────────────────── + +/// A colour the extracted lines can take (ACI; 256 ByLayer, 0 ByBlock). +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct LineColor(pub i16); + +impl LineColor { + pub const ALL: [LineColor; 9] = [ + LineColor(256), + LineColor(0), + LineColor(1), + LineColor(2), + LineColor(3), + LineColor(4), + LineColor(5), + LineColor(6), + LineColor(7), + ]; +} + +impl fmt::Display for LineColor { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let label = match self.0 { + 256 => t!("ByLayer"), + 0 => t!("ByBlock"), + 1 => t!("Red"), + 2 => t!("Yellow"), + 3 => t!("Green"), + 4 => t!("Cyan"), + 5 => t!("Blue"), + 6 => t!("Magenta"), + _ => t!("White"), + }; + f.write_str(label.as_ref()) + } +} + +/// The dialog's fields; numbers as typed. +pub struct PcSectionState { + pub perimeter: bool, + pub max_points: String, + /// "Use Current" first, then the drawing's layers. + pub layers: Vec, + pub layer: String, + pub color: LineColor, + pub polylines: bool, + pub width: String, + pub min_length: String, + pub connect: String, + pub angle: String, + pub preview: bool, +} + +pub fn view_pc_section<'a>(state: &'a PcSectionState, sizing: crate::ui::modal::ModalSizing) -> Element<'a, Message> { + let extract = card( + t!("Extract").into_owned(), + segmented( + vec![(false, t!("Entire cross section").into_owned()), (true, t!("Perimeter only").into_owned())], + state.perimeter, + PdfDialogMsg::SecPerimeter, + ), + ); + let points = state.max_points.trim().parse::().unwrap_or(18_000.0).clamp(1_000.0, 200_000.0); + // ponytail: the time shown scales with the points (18000 ≈ 1 minute, as + // the reference shows it); the real rate depends on the machine. + let minutes = (points / 18_000.0).ceil().max(1.0) as u32; + let max_points = card( + t!("Maximum points to process").into_owned(), + column![ + row![ + iced::widget::slider(1_000.0..=200_000.0, points, |v| msg(PdfDialogMsg::SecMaxPoints( + ((v / 1_000.0).round() * 1_000.0).to_string() + ))) + .step(1_000.0) + .width(Fill), + text_input("", &state.max_points) + .on_input(|v| msg(PdfDialogMsg::SecMaxPoints(v))) + .size(11) + .padding([4, 8]) + .width(Length::Fixed(90.0)) + .style(field_style), + ] + .spacing(8) + .align_y(iced::Center), + row![ + text(t!("Faster")).size(10).style(muted_style), + Space::new().width(Fill), + text(t!("More accurate")).size(10).style(muted_style), + Space::new().width(Fill), + text(crate::tf!("Estimated time: {count} min", count = minutes)).size(10).style(muted_style), + ], + ] + .spacing(6), + ); + let layer = pick_list(Some(state.layer.clone()), state.layers.clone(), |n: &String| n.clone()) + .on_select(|n| msg(PdfDialogMsg::SecLayer(n))) + .text_size(12) + .padding([4, 8]) + .width(Fill); + let color = pick_list(Some(state.color), LineColor::ALL.to_vec(), |c: &LineColor| c.to_string()) + .on_select(|c| msg(PdfDialogMsg::SecColor(c))) + .text_size(12) + .padding([4, 8]) + .width(Fill); + let labelled = |label: std::borrow::Cow<'static, str>, control: Element<'a, Message>| -> Element<'a, Message> { + row![text(label).size(11).style(muted_style).width(Length::Fixed(70.0)), control] + .spacing(6) + .align_y(iced::Center) + .into() + }; + let output = card( + t!("Output geometry").into_owned(), + column![ + labelled(t!("Layer"), layer.into()), + labelled(t!("Color"), color.into()), + segmented( + vec![(false, t!("Lines").into_owned()), (true, t!("2D Polylines").into_owned())], + state.polylines, + PdfDialogMsg::SecPolylines, + ), + field(t!("Polyline width").into_owned(), &state.width, state.polylines, 150.0, |v| msg(PdfDialogMsg::SecWidth(v))), + ] + .spacing(8), + ); + let pick = |connect: bool| { + button(text("⌖").size(12)) + .on_press(msg(PdfDialogMsg::SecPick(connect))) + .style(button_style(false)) + .padding([4, 8]) + }; + let tolerances = card( + t!("Extraction tolerances").into_owned(), + column![ + row![field(t!("Minimum line length").into_owned(), &state.min_length, true, 170.0, |v| msg(PdfDialogMsg::SecMinLength(v))), pick(false)] + .spacing(6) + .align_y(iced::Center), + row![field(t!("Connect lines tolerance").into_owned(), &state.connect, true, 170.0, |v| msg(PdfDialogMsg::SecConnect(v))), pick(true)] + .spacing(6) + .align_y(iced::Center), + row![ + field(t!("Collinear angle tolerance").into_owned(), &state.angle, true, 170.0, |v| msg(PdfDialogMsg::SecAngle(v))), + text("0–10°").size(10).style(muted_style) + ] + .spacing(6) + .align_y(iced::Center), + ] + .spacing(8), + ); + let body = column![ + row![extract, max_points].spacing(10), + row![output, tolerances].spacing(10), + ] + .spacing(10); + let footer = row![ + button(text("?").size(12)) + .on_press(msg(PdfDialogMsg::Help("pcsection"))) + .style(button_style(false)) + .padding([5, 11]), + chip(t!("Preview result").into_owned(), state.preview, msg(PdfDialogMsg::SecPreview(!state.preview))), + Space::new().width(Fill), + dialog_button(t!("Cancel"), Message::CloseModal, false), + dialog_button(t!("Create"), msg(PdfDialogMsg::SecCreate), true), + ] + .spacing(8) + .align_y(iced::Center); + column![body, footer].spacing(10).padding([10, 12]).width(sizing.width).into() +}