Wybieranie elementów, Visual Lisp, edycja bloku


Recommended Posts

Napotkałem pewien problem. Pewnie dla Was to nie-problem więc może mi pomożecie.

Wybrałem zbiór wskazań na pomocą (ssget...), w dalszej fazie operuję na wybranych poszczególnych elementach rysunku za pomocą Visual Lisp (obiektów).

Wszystko jest ok. Tylko zrodziło się jedno "ale": Jeśli jestem (jako użytkownik) w trybie edycji jakiegoś bloku ("wewnątrz" bloku) to do zbioru ssget łapane są również elementy będące poza blokiem, których edycja powinna być zablokowana. Operuję przecież tylko na elementach edytowanego bloku.Tak się dzieje z normalnymi poleceniami, ale funkcje VLisp działają wtedy nadal na wszystkich obiektach - łącznie tych z zewnątrz.

Jak wyselekcjonować z ssget tylko elementy wchodzące w w skład edytowanego bloku?
Albo jak sformułować ssget, aby wybrane zostały tylko elementy będące w bloku w trybie edycji?

Pozdrawiam

Link to comment
Share on other sites

Zasada działania jest prościutka. Funkcja na wskazanych blokach wykonuje MIRROR względem osi Y bloku. Poniżej tylko ta część dotycząca wyboru elementów.
W głównej funkcji kiedyś wykonywałem (command ..... Mirror i wtedy wszystko działało dobrze również przy edycji bloku (tzn polecenie mirror nie było wykonywane). Ale postanowiłem zmodernizować kod i przejść na operacje na obiektach zamiast (command....  

(defun C:ZYXAK_MT_MirrorY ( / OBJECT f ss)
	(ZYXAK_Start)
	(setq ss *ZYXAK_Selected*)
	(if (= ss nil)
		(progn 
			(setq ss (ssget
				(list 
					(cons 0 "INSERT")
				)
			))
			(if (= ss nil) (exit))
		)
	)
	(setq f 0)
	(repeat (sslength ss)
		(setq OBJECT (vlax-ename->vla-object (ssname ss f)))
		(ZYXAK_MT_MirrorY OBJECT)
		(setq f (1+ f))
	)
)
Link to comment
Share on other sites

W tym przypadku polecam (jak zwykle) CADPL-Pack (https://kojacek.wordpress.com/cadpl-pack/). Tutaj będzie to funkcja o nazwie cd:BLK_GetEntity. Tworzy ona listę obiektów tworzących blok. W wywołaniu repeat (ale dlaczego? - użyłbym foreach), wystarczy wtedy porównać czy obiekt ze zbioru wskazań znajduje się na liście (i wtedy wykonać jakąś operację), czy nie (i wtedy nic z nim nie robić).

Na marginesie, dlaczego takie zabawy? - zmian w bloku można dokonać przecież lispem "po cichu", bez użytkownika, czyli bez edycji bloku, bez ssget'ów, itp. i innych problemów.

Link to comment
Share on other sites

Taki algorytm (porównanie z listą obiektów tworzących blok) jest możliwe, ale jak uzyskać nazwę bloku, którą użytkownik właśnie edytuje (jeśli edytuje)?

Ale tu chodzi o to żeby użytkownik wybrał elementy do edycji (a przecież możne to zrobić będą np. w edycji innego bloku). Więc nie chodzi tu o robienie czegoś "po cichu".

repeat? - a jakoś takie przyzwyczajenie.... ;)

Pozdr.

Link to comment
Share on other sites

Taki algorytm (porównanie z listą obiektów tworzących blok) jest możliwe, ale jak uzyskać nazwę bloku, którą użytkownik właśnie edytuje (jeśli edytuje)?

Ale tu chodzi o to żeby użytkownik wybrał elementy do edycji (a przecież możne to zrobić będą np. w edycji innego bloku). Więc nie chodzi tu o robienie czegoś "po cichu".

repeat? - a jakoś takie przyzwyczajenie.... ;)

Pozdr.

  1. Przyznam że nie rozumiem. Jeśli klikacz siedzi i klika (czyli wybiera) to skąd problem z ssget-em? Niech klika i wybierze w końcu.
  2. W AutoCAD jest zmienna REFEDITNAME która zwraca nazwę bloku (ZOdn) edytowanego, lub "". Jeżeli blok jest edytowany w edytorze bloków, to o jego stanie informuje zmienna BLOCKEDITOR (0 lub 1)
Link to comment
Share on other sites

Niezrozumienie problemu wynika może z błędu działania ZWcada (nie wiem jak skrypt zachowałby się na AC), więc może jeszcze raz wyjaśnię:

Klikacz rysuje rysunek. Ma w rysunku powstawiane jakieś bloki A oraz blok B który składa się z bloków C (bloki zagnieżdzone. Jeśli teraz klikacz wejdzie w edycję bloku B i będzie chciał zastosować moją funkcję na blokach C to może je wskazać np. oknem. jeśli w obszarze okna znajdzie się również blok A to mimo, że jest on poza blokiem B to zostanie zaznaczony i dodany do ssget. (Wg mnie tak nie powinno być - nie wiem jak jest w AC). Podobnie jeśli klikacz wskazuje klikając poszczególne bloki to może w tym momencie (w trakcie edycji bloku B) zaznaczyć blok A (dla mnie to nie logiczne).

I teraz jeśli na takim zbiorze wyboru działała moja funkcja to w przypadku wykonywania operacji za pomocą (command MIRROR.... nic się z blokami A nie działo. Były zaznaczone ale nie podlegały modyfikacji. Więc OK. A teraz (command zastąpiłem  Metodą VL Mirror, co spowodowało, że lustro zadziałało nie tylko na blokach C, ale również na bloku A (wybranym przypadkowo). 

Już nie wspomnę o tym, że Metoda Mirror robi kopię bloku co jest niewygodne, bo ta kopia ląduje w rysunku, a nie w definicji bloku B.

Nie wiem czy teraz jest już jasna sprawa.

Ogólnie dochodzę do wniosku, że wrócę znów chyba do (command MIRROR bo to wygodniejsze....

Link to comment
Share on other sites

Rozwiązania widzę co najmniej dwa, a właściwie trzy (jako mariaż pierwszego i drugiego):

  1. Wspomniana wcześniej funkcja CADPL-Pack,owa, do "ogolenia" ssget'a z elementów nie będących częścią definicji edytowanego bloku. To rozwiązuje sprawę na poziomie elementarnym.
  2. Utworzenie zbioru wskazań za pomocą bardziej złożonego wywołania funkcji ssget - np. z wykluczeniem nazw pewnych bloków, obiektów, obiektów na warstwie itp. Np. "kulturalnie" zdefiniowany blok ma obiekty na warstwie "0" (w definicji). Zachowując higieniczność w malowaniu (nic nigdy nie jest na warstwie "0"), podczas edycji bloku, dobieramy się do jego obiektów w definicji, czyli na warstwie "0", właśnie. Oczywiście to mógłby być jeden z warunków, może być ich więcej.
  3. Kombinacja tych powyższych: inteligentny ssget, potwierdzony (czy zweryfikowany) listą.
Link to comment
Share on other sites

Proszę zobaczyć jak działa program z załącznika. Cały trik oparty jest na takiej sztuczce, że uruchamiając polecenie refedit zapisujemy uchwyt elementu ostatnio zapisanego do bazy, następnie w funkcji odfiltrowujemy wszystkie elementy, których uchwyty,  zostały dodane przed rozpoczęciem działania funkcji refedit.

(setq g_lastHandle nil g_tmpHandel nil)
(defun callbackStart(obj lst)
  (if (= "REFEDIT" (car lst))
    (setq g_lastHandle (cdr (assoc 5 (entget (entlast)))))
  )
)

(defun callbackEnd(obj lst)
  (if (= "REFCLOSE" (car lst))
    (progn
      (setq g_tmpHandel g_lastHandle)
      (setq g_lastHandle nil)
    )
  )
)

(defun callbackAbort(obj lst)
  (if (= "REFEDIT" (car lst))
    (setq g_lastHandle nil)
  )
  (if (= "REFCLOSE" (car lst))
    (setq g_lastHandle g_tmpHandel)
  )
)

(if (null refeditDetect) (setq refeditDetect (vlr-command-reactor nil '((:vlr-commandWillStart . callbackStart)
                                                                        (:vlr-commandEnded . callbackEnd)
                                                                        (:vlr-commandCancelled . callbackAbort)
                                                                        (:vlr-commandFailed . callbackAbort)))))
(defun getRefeditSS( / elst en i len ss)
  (setq ss (ssget))
  (if g_lastHandle
    (progn
      (setq i 0 len (sslength ss))
      (setq elst nil)
      (while (< i len)
        (setq en (ssname ss i))
        (setq elst (cons en elst))
        (setq i (1+ i))
      )
      (foreach en elst
        (if (<= (cdr (assoc 5 (entget en))) g_lastHandle)
          (ssdel en ss)
        )
      )
    )
  )
  ss
)

(defun c:foo()  
  (print (sslength (getRefeditSS) ))  
  (princ)
)

ssget_refedit.lsp

Link to comment
Share on other sites

Nie mogę na AutoCAD-zie sprawdzić ani jednego rozwiązania... z prostej przyczyny - AutoCAD działa poprawnie i w trybie edycji lokalnej bloku (REFEDIT), po prostu nie jest możliwy wybór innych obiektów niźli tych z zestawu roboczego. Czyli generalnie jest to przypadłość ZwCAD-a, może po prostu mogliby to poprawić? A wtedy żadna protetyka nie będzie potrzebna.

Link to comment
Share on other sites

Nie mogę na AutoCAD-zie sprawdzić ani jednego rozwiązania... z prostej przyczyny - AutoCAD działa poprawnie i w trybie edycji lokalnej bloku (REFEDIT), po prostu nie jest możliwy wybór innych obiektów niźli tych z zestawu roboczego. Czyli generalnie jest to przypadłość ZwCAD-a, może po prostu mogliby to poprawić? A wtedy żadna protetyka nie będzie potrzebna.

Właśnie chodziło mi o sprawdzenie, czy to jest błąd ZWcada, czy tak to (wybieranie) działa w AutoCADzie i w ZW zrobili też tak dla zachowania kompatybilności, mimo że to nie logiczne.

Teraz już wiem. Dziękuje.

Dziękuję również za przedstawienie w sumie 4 rozwiązań w tym w zasadzie gotowego kodu. Najbardziej odpowiada (na podstawie idei, bo jeszcze nie testowałem w praktyce) rozwiązanie nr 1 i 4. Zapewne któreś wykorzystam. Dziękuję rozmówcom.

I tak już właściwie poza tematem wątku napiszę o moim indywidualnym podejściu opisanym w rozwiązaniu 2, a mianowicie "kulturalnym" definiowaniu bloków. Wiem, że to będzie bluźnierstwo dla ortodoksyjnych ekspertów cada (sam miałem kiedyś taki ortodoksyjny pogląd), ale dziś uważam, że definicje bloków wcale nie powinny być robione tylko na warstwie "0". Zdanie zmieniłem analizując potrzeby dostosowania sposobu pracy do lepszego, wygodniejszego i bardziej intuicyjnego tworzenia rysunku (mówię tu akurat o 2D). Odejście od przykazania lokowania wszystkiego w bloku na warstwie "0" otwiera olbrzymie nowe możliwości budowania strukturalnego rysunku w zwykłym prostym CADzie bez skomplikowanych nakładek. Połączenie zagnieżdżania bloków, systemowego nazewnictwa warstw i pozbycie się ograniczeń związanych z rysowaniem na "0" pozwala całkowicie zmienić podejście do rysunku i tworzyć go (ja to nazywam) bardziej obiektowo. Struktura rysunku odpowiada strukturze (w moim przypadku) projektowanego budynku. Dzieje się to za pomocą współdziałania razem idei warstw i bloków. Ciężko tą idee opisać słowami i to nie miejsce na taki wątek, ale kiedy po jej opracowaniu spojrzałem w dawne czasy swoich pierwszych rysunków robionych ponad 20 lat temu, to zaskoczyło mnie, ile można jeszcze wyciągnąć nowego z właściwie niezmienionego w swoim głównym działaniu CADa dodając jedynie pewną własną myśl intelektualną wykorzystującą te same narzędzia, ale w inny trochę sposób i z innym podejściem

Pozdrawiam. 

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...