entmod na wielu obiektach


Recommended Posts

Dzień dobry.

Próbuję wykonać pewną operację na wielu powierzchniach 3DFace. Dla przykładu pomnożyć współrzędną "Z" wierzchołków razy 10. Korzystając z kilku podpowiedzi:
https://www.zwcad.pl/help/lisp-help/246-subst.html
http://forums.augi.com/showthread.php?120834-How-to-know-name-of-Entity-by-ssget
Stworzyłem coś takiego:

(defun c:zz ()
(if (setq ssSelections (ssget (list (cons 0 "3DFACE"))))
 (repeat (setq intCount (sslength ssSelections))
  (setq intCount     (1- intCount)
        entSelection (ssname ssSelections intCount)
        lstEntity    (entget entSelection)
  )
   		;współrzędne wierzchołka 1
		(setq wierzcholek1 (assoc 10 lstEntity))
			(setq x1 (nth 1 wierzcholek1))
			(setq y1 (nth 2 wierzcholek1))
			(setq z1 (nth 3 wierzcholek1))
		;współrzędne wierzchołka 2
			(setq wierzcholek2 (assoc 11 lstEntity))
			(setq x2 (nth 1 wierzcholek2))
			(setq y2 (nth 2 wierzcholek2))
			(setq z2 (nth 3 wierzcholek2))
		 
    ;podmiana punktu 1
(setq lstEntity (subst (cons 10 (list	x1 y1 (* z1 10)) (assoc '10 lstEntity ) lstEntity ) ))
(entmod lstEntity)
	;podmiana punktu 2
(setq lstEntity (subst (cons 11 (list	x2 y2 (* z2 10)) (assoc '11 lstEntity ) lstEntity ) ))
(entmod lstEntity)

 );koniec repeat
 );koniec if
 (print)
);Koniec

W powyższym kodzie pominąłem dwa ostatnie punkty. Chciałem pokazać tylko ideę.
Co robię źle, że to nie działa?

Pozdrawiam

Link to comment
Share on other sites

Prawie wszystko. Począwszy od:
1) braku zmiennych lokalnych (zobacz: https://kojacek.wordpress.com/2015/12/20/symbole-zmienne/). 
2) Potem pomysł z mnożeniem wartości współrzędnej z. Operacje dodawania/odejmowania wydają się być chyba bardziej naturalne (sprawdź mnożenie 1 i 0 przez dowolną wartość). Na marginesie: zmiana składowej Z wszystkich punktów obiektu, o tę samą wartość, to w rzeczywistości przesunięcie go w przestrzeni - to można też robić prościej (command MOVE, lub vla-Move dla ActiveX)
3) Ponadto ja bym nie użył (ze względu na wydajność) repeat, tylko raczej foreach dla listy otrzymanej ze zbioru wskazań. 
4) Tak samo zmieniłbym całą listę, i tylko raz wywołał entmod
Oczywiście dwa ostatnie punkty nie są szczególnymi błędami.

Poczytaj też o: https://kojacek.wordpress.com/2015/11/04/cadpl-pack/ Jest tam parę dość użytecznych rzeczy.
 

Edited by kojacek
Link to comment
Share on other sites

Oczywiście zajrzę na Pańską stronę. Każda dodatkowa wiedza jest cenna.
Do tej pory myślałem, że deklarowanie zmiennych to pomoc przy dużych kodach, a nie konieczność.
Czy to może być powodem nie działania programu? 
Program działa do linijki: podmiana punktu 1
Natomiast mnożenie zmiennej "Z" to tylko przykład.

Pozdrawiam  

Link to comment
Share on other sites

Zobacz to:

(setq NowyZ 152)

(defun C:ZZ (/ ss :chFaceZ)
  (defun :chFaceZ (En Val / l d n p)
    (setq l '(10 11 12 13)
          d (entget En)
          n (vl-remove-if '(lambda (%)(member (car %) l)) d)
          p (vl-remove-if-not '(lambda (%)(member (car %) l)) d)
          p (mapcar '(lambda (%)
                       (list (car %)(cadr %)(caddr %)(+ Val (cadddr %)))) p)
    )
    (entmod (append n p))
  )
  (if
    (setq ss (ssget '((0 . "3DFACE"))))
    (foreach % (cd:SSX_Convert ss 0)
      (:chFaceZ % NowyZ)
    )
  )
  (princ)
)

Dodaje wartość zmiennej globalnej NowyZ do składowej z każdego wierzchołka wybranych 3DFace. Wykorzystuje cd:SSX_Convert  ze wspomnianego CADPL-Pack'a

Link to comment
Share on other sites

Mój poziom wiedzy o lispie jest o kilka poziomów za niski, żeby w 100% zrozumieć powyższy kod... a może strach ma wielkie oczy.
Żeby ruszyć dalej z nauką muszę wiedzieć gdzie robię błędy na obecnym etapie.

Tak czy siak dziękuję za pomoc

PS docelowy kod ma zmieniać wsp wierzchołków z takich:
W1:  x1=5.12345678  y1=3.23456789 z1=7.42345678
na takie:
W1:  x1=5.12000000  y1=3.23000000  z1=7.42000000
Czyli niewielkie przesunięcie. 
Uważałem, że nie ma potrzeby pisać całego kodu, dlatego posłużyłem się przykładem (* z 10)

Link to comment
Share on other sites

Problemem w kodzie z pierwszego przykładu jest:
LISP czyli  Lost In Stupid Parentheses :wink:Po uruchomieniu kodu w pasku poleceń pojawia się :

Error: too many arguments

czyli któraś funkcja została wywołana ze zbyt dużą ilością argumentów. Pozostaje nam znaleźć która.
Tak na pierwszy rzut oka wyglądało OK, więc spróbowałem wykonać kod "po linijce"
Okazało się, że komunikat wyświetla linijka

(setq lstEntity (subst (cons 10 (list x1 y1 (* z1 10))  (assoc '10 lstEntity ) lstEntity ) ))

Notepad++ ma kolorowanie składni i podświetlanie nawiasów. Więc łatwo widać, że to cons, ma nawias zbyt daleko.

Notepad++.png

Czyli cały poprawiony kod:

(defun c:zz ()
(if (setq ssSelections (ssget (list (cons 0 "3DFace"))))
 (repeat (setq intCount (sslength ssSelections))
  (setq intCount (1- intCount)
        entSelection (ssname ssSelections intCount)
        lstEntity (entget entSelection)
  )
           ;współrzędne wierzchołka 1
        (setq wierzcholek1 (assoc 10 lstEntity))
            (setq x1 (nth 1 wierzcholek1))
            (setq y1 (nth 2 wierzcholek1))
            (setq z1 (nth 3 wierzcholek1))
        ;współrzędne wierzchołka 2
            (setq wierzcholek2 (assoc 11 lstEntity))
            (setq x2 (nth 1 wierzcholek2))
            (setq y2 (nth 2 wierzcholek2))
            (setq z2 (nth 3 wierzcholek2))
         
    ;podmiana punktu 1
(setq lstEntity (subst (cons 10 (list x1 y1 (* z1 10) ))  (assoc '10 lstEntity ) lstEntity ) )
(entmod lstEntity)
    ;podmiana punktu 2
(setq lstEntity (subst (cons 11 (list x2 y2 (* z2 10) ) ) (assoc '11 lstEntity ) lstEntity ) )
(entmod lstEntity)

 );koniec repeat
 );koniec if
 (print)
);Koniec

 

Link to comment
Share on other sites

Lost In Stupid Parentheses  - to moje nowe motto;)

Nie mogę uwierzyć,że to o to chodziło.
Co do powyższego kodu jest jeszcze jeden bug. Zmienia tylko jeden wierzchołek. Prawdopodobnie dlatego, że przy drugim punkcie odwołuję się do lstEntity (przed zmianą 1 punktu).
Rozwiązałem to tak:

(defun ChangeVx ( NrVx / )

 (repeat (setq intCount (sslength ssSelections))
  (setq intCount     (1- intCount)
        entSelection (ssname ssSelections intCount)
        lstEntity    (entget entSelection)
   )
  		;Vertex 
		(setq wierzcholek (assoc NrVx lstEntity))
			(setq x1 (nth 1 wierzcholek))
			(setq y1 (nth 2 wierzcholek))
			(setq z1 (nth 3 wierzcholek))
 
    ;podmiana punktu 
(setq nowaDef (subst (cons NrVx (list		(atof (rtos x1 2 2))
										(atof (rtos y1 2 2))
										(atof (rtos z1 2 2))
															)) (assoc 'NrVx lstEntity ) lstEntity ))
(setq nowaDef (append lstEntity (list (cons NrVx (list 	(atof (rtos x1 2 2))
														(atof (rtos y1 2 2))
														(atof (rtos z1 2 2)))) ) ) )

(entmod nowaDef)
 
 );koniec repeat
 (print)
);

(defun c:zz ()
(setq ssSelections (ssget (list (cons 0 "3DFACE"))))
(setq NrVx 10)
(repeat 4
	(ChangeVx NrVx )
	(setq NrVx (1+ NrVx))
);end repeat
);KONIEC

A zamiast:
(atof (rtos x 2 2))
można tak:
(/ (fix (* x 100.)) 100.0)

Dziękuję za wszystkie podpowiedzi

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...