Aller au contenu

Messages recommandés

Posté(e)

Bonjour à tous

 

Pour des raisons compliquées, je dois utiliser (ssget "_P").

Seulement dans le cas où la sélection utilisateur est vide, cette fonction renvoie tout de même le jeu de sélection précédent au lieu d'un jeu vide...

 

Y a t-il un moyen de purger la sélection précédente ?

J'ai essayé (gc) et (vla-update(vlax-get-acad-object)), ça ne marche pas..

 

 

Posté(e)

Bonjour,

 

Je ne pense pas qu'il soit possible de réinitialisé le jeux de sélection "Précédent".

 

Il te faut contrôler tes propres jeux de sélection dans ton code.

 

(ssadd) sans argument de nom d'entité va te créer un jeu vide. Par exemple (setq js (ssadd)) JS sera vide!

 

A partir de là, dans ton code tu pourra ajouter (ou enlever) des entités dans ton jeu de sélection

 

Un exemple possible (sans voir de code, difficile de t'orienter)

 

 

((lambda ( / js js_tmp n)
 (setq js (ssadd))
 (setq js_tmp (ssget))
 (if js_tmp (repeat (setq n (sslength js_tmp)) (setq js (ssadd (ssname js_tmp (setq n (1- n))) js))))
 (sssetfirst nil js)
))

Choisissez un travail que vous aimez et vous n'aurez pas à travailler un seul jour de votre vie. - Confucius

Posté(e)

Merci pour le rappel (ssadd), mais comme je disais je dois utiliser (ssget "_P") au lieu d'un ssget 'normal' (c'est après un appel de commande).

La différence est que si la sélection est vide, (ssget) renvoie nil alors que (ssget "_P") renvoie la sélection d'avant, qui n'a rien à voir..

Posté(e)

Extrait de l'aide sur la sélection:

 

Précédent

Sélectionne le jeu de sélection le plus récent. Le jeu de sélection Précédent est effacé par toutes les opérations supprimant des objets du dessin.

 

Le programme mémorise l'espace dans lequel chaque jeu de sélection a été défini : espace papier ou espace objet. Le jeu de sélection Précédent n'est pas pris en compte si vous changez d'espace.

 

 

Ce qui laisserai penser que si dans ton code tu crée une entité dans l'espace courant. Un point par exemple par (entmake) ou autre puis que tu fasse (entdel (entlast)), le jeu de sélection "Précédent" serait alors remis à nil (vide)

 

Essayé rapidement et effectivement ça à l'air de fonctionner. Je pense quand même qu'il faut s'assurer que le calque en cours ne soit pas verrouillé (pas testé). Je pense aussi que c'est la seule voie à creuser pour répondre a ta question.

Choisissez un travail que vous aimez et vous n'aurez pas à travailler un seul jour de votre vie. - Confucius

Posté(e)

Merci, je n'avais pas pensé à regarder dans l'aide général..

 

Par contre.. ça ne marche pas chez moi.

J'ai testé avec ce code qui renvoie le 1er objet de (ssget "_P") avant et après création point.. chez moi ça ne purge pas

 

 
((lambda()
  (print (ssname (ssget "_P") 0))
  (entmake '((0 . "POINT") (10 0.0 0.0 0.0)))
  (entdel (entlast))
  (print (ssname (ssget "_P") 0))
  (princ)
))

Posté(e)

Salut,

 

Je ne comprends pas ce qui peut "t'obliger" à utiliser (ssget "_P").

Si tu assignes à une variable le jeu de sélection précédent :

(setq ss (ssget))

tu peux toujours vérifier si le jeu de sélection est vide :

(if ss ...)

 

Tu dis y être obligé après un appel de commande,

cet appel fait-il parti de ton programme ?

ou le lancement du programme est provoqué par l'appel (réacteur) ?

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Par contre.. ça ne marche pas chez moi.

 

En fait avec (entdel) cela ne fonctionne pas aussi chez moi.

 

Cette fonction (entdel) est un peu particulière en lisp. En effet elle peut aussi restorer une entité supprimé tant que le nom de l'entité n'est pas perdu (sauvé dans une variable et durant l'édition du dessin en cours)

Est aussi il est bien spécifié dans l'aide de entdel que l'on ne peut pas effacer une entité complexe.

Cela montre bien que cette commande ne peut pas avoir de bons effets sur par exemple un bloc ou une ancienne polyligne qui seraient dans le jeu de sélection précédent. Ceci explique cela ! :P

 

Si tu utilises la commande SELECT choisis des objets et applique le code suivant en mettant la commande ENTMAKE et ERASE en remarque (rem => ";" en début de ligne), tu verras que les grips sont activés sur la sélection précédente.

Refais la même démarche mais sans les rems, le jeux de sélection précèdent sera vide.

 

((lambda()
 (entmake '((0 . "POINT") (10 0.0 0.0 0.0) (60 . 1)))
 (setvar "CMDECHO" 0)
 (command "_.erase" "_last" "")
 (setvar "CMDECHO" 1)
 (sssetfirst nil (ssget "_P"))
 (prin1)
))

 

Peut être qu'une commande VLA serait plus efficace que (entdel) et plus élégant que (command), pas testé....

Choisissez un travail que vous aimez et vous n'aurez pas à travailler un seul jour de votre vie. - Confucius

Posté(e)

Encore merci Bonuscad, ça m'a effectivement l'air de marcher comme ça.

 

Je l'ai refait avec vla-delete et toujours avec (print(ssget"_P")) avant/après, ça donne ça (pas sûr que ce soit mieux)...

 
((lambda()
 (print (ssget "_P"))
 (entmake '((0 . "POINT") (10 0.0 0.0 0.0) (60 . 0)))
 (vla-delete (vlax-ename->vla-object (ssname(ssget "_L")0)))
 (print (ssget "_P"))
 (princ)
))

Pour voir la "purge" de (ssget"_P") il faut d'abord éditer un objet avec une commande (et non pas un déplacement par saisie)

D'autre part si on remplace (ssname(ssget "_L")0) par (entlast) ça ne marche plus.

Tout ça est plutôt curieux.. et confirme qu'il faut parfois aller chercher des solutions relativement tordues...

 

Pour répondre aux questions de gile.. il s'agit bien de récupérer les objets traités par un appel de commande, l'appel est lancé par mon programme et la récupération (ssget"_P") est lancée par un réacteur commandEnded.. compliqué..

Posté(e)

Salut,

 

Si l'appel de la commande est lancé depuis un programme, tu peux assigner le jeu de sélection à une variable globale :

(setq *selset* (ssget))

(command ... *selset* ....)

 

Puis dans la fonction callback de ton réacteur, tester la validité du jeu de sélection et le supprimer après usage :

(if *selset* ...) (setq *selset* nil)

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Oui.. mais non : la sélection est faites par la commande justement, d'où le (ssget"_P") placé après.

Et donc avec (ssget"_P") il faut purger avant pour le cas d'une sélection vide...

Posté(e)

Si tu donnais un peu plus de détails, on pourrait peut-être t'aider mieux. Des fois on se focalise tellement sur ce qu'on pense être le problème qu'on ne peut voir une solution qui le contournerait.

C'est quoi la commande ?

Avec quelle fonction est elle appelée (command ou vl-cmdf) ?

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Si je te dis quel est la commande tu vas me trouver encore plus tordu.. en fait la commande est un SELECT !

 

Alors voilà ce que je veux faire..

Le déroulement de la commande est comme celui de _pedit par exemple : quand tu survoles une entité elle est highlightée , et quand tu cliques dessus elle est traitée.. (bref la structure est une boucle grread).

Pour pouvoir traiter plusieurs objets il y a une option Multiple... mais ce que je veux en plus, qui n'est pas dans _pedit, et qui s'avère très pratique et très immédiat à l'usage... c'est qu'on puisse aussi sélectionner les entités (multiples) simplement en cliquant sur du vide : si tu cliques à côté d'un objet tu lances une sélection normale.

Or comment faire ça ?

Il n'y a pas d'option (ssget) qui permette de faire une sélection normale (windows-capture..) en spécifiant juste le 1er point et en attendant le 2è, pas que je sache...

Voilà pourquoi je suis parti sur cet appel de commande* "_SELECT" avec toutes les complications qui s'en suivent : c'est pour faire (command "_SELECT" pt0) !

 

Si tu as plus simple je suis preneur..

 

* pour ce qui est de command ou vl-cmdf, je ne connais pas la différence en fait

Posté(e)

J'avais fait une simulation des fenêtres de sélection avec grread.

 

La fonction gr-sel-display requiert un argument : un point dans le SCU courant qui sert de base à la fenêtre. Elle retourne un liste dont le premier élément est le mode de sélection (capture ou fenêtre) et les autres les sommets de la fenêtre.

Pour un fonctionnement cohérent quelle que soit la vue courante (vues 3d) certaines conversions de coordonnées sont nécessaires ainsi que la routine ilp.

 

On peut utiliser la liste retourner par gr-sel-display pour faire une sélection avec ssget comme dans l'exemple suivant.

 

(defun c:test (/ pt gsd ssmod)
 (and
  (setq pt (getpoint "\nPremier coin: "))
   (setq gsd (gr-sel-display pt))
   (setq ss (ssget (car gsd) (cdr gsd)))
   (sssetfirst ss ss)
 )
 (princ)
)

 

La fonction gr-sel-display

 

;|
gr-sel-display (gile)
Utilisation de grread pour simuler une fenêtre de sélection

Argument :
un point (coordonnées SCU courant)

Retour :
une liste dont le premier élément correspond au mode de sélection ("_CP" ou "_WP")
et les éléments suivants les sommets de la fenêtre (coordonnées SCU courant)

Exemple d'utilisation :
(setq pt  (getpoint)
     gsd (gr-sel-display pt)
     ss  (ssget (car gsd) (cdr gsd))
)
|;

(defun gr-sel-display ( pt1ucs / gr pt1ucs pt2ucs pt3ucs pt4ucs pt1view pt2view pt3view pt4view ssmode result)
 (while (and (setq gr (grread T 12 0)) (/= (car gr) 3))
   (redraw)
   (setq pt3ucs  (cadr gr)
  pt1view (trans pt1ucs 1 2)
  pt3view (trans pt3ucs 1 2)
  pt2view (list (car pt3view) (cadr pt1view) (caddr pt1view))
  pt4view (list (car pt1view) (cadr pt3view) (caddr pt3view))
  pt2ucs  (trans (ilp pt2view
		      (mapcar '+ pt2view '(0 0 1))
		      (trans '(0 0 0) 1 2)
		      (trans '(0 0 1) 1 2 T)
		 )
		 2
		 1
	  )
  pt4ucs  (trans (ilp pt4view
		      (mapcar '+ pt4view '(0 0 1))
		      (trans '(0 0 0) 1 2)
		      (trans '(0 0 1) 1 2 T)
		 )
		 2
		 1
	  )
  ssmode (if (		   "_CP"
	   "_WP"
	 )
   )
   (grvecs
     (list (if	(= ssmode "_CP")
      -255
      255
    )
    pt1ucs
    pt2ucs
    pt2ucs
    pt3ucs
    pt3ucs
    pt4ucs
    pt4ucs
    pt1ucs
     )
   )
 )
 (redraw)
 (list ssmode pt1ucs pt2ucs pt3ucs pt4ucs)
)

;; VXV
;; Retourne le produit scalaire (réel) de deux vecteurs
;;
;; Arguments : deux vecteurs

(defun vxv (v1 v2) (apply '+ (mapcar '* v1 v2)))

;; ILP (gile)
;; Retourne le point d'intersection de la droite définie par p1 p2
;; et du plan défini par un point et sa normale.
;;
;; Arguments
;; p1 et p2 : les points définissant la droite dont on cherche l'intersection
;; org : un point quelconque du plan d'intersection
;; nor : le vecteur normal du plan d'intersection

(defun ilp (p1 p2 org nor / scl)
 (if (and
(/= 0 (setq scl (vxv nor (mapcar '- p2 p1))))
(setq scl (/ (vxv nor (mapcar '- p1 org)) scl))
     )
   (mapcar (function (lambda (x1 x2) (+ (* scl (- x1 x2)) x1)))
    p1
    p2
   )
 )
)

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

En effet c'est efficace, et ça peut être ça..

Ton code* a l'avantage de ne pas sortir de la boucle (de ne pas perdre les variables), et le principal inconvénient est juste qu'on n'a pas le vert-bleu de la capture !

 

Merci beaucoup, je vais voir si je vais pas l'intégrer vu que ça marche toujours à moitié mon bricolage à réacteurs...

 

* ajouter l'argument à l'appel (gr-sel-display) et ajouter la fonction vxv

 

__________________

Question: mais pourquoi projeter (ilp) sur le plan de la vue pour obtenir les points de (ssget) ?

 

[Edité le 11/5/2009 par krunch]

Posté(e)

Question: mais pourquoi projeter (ilp) sur le plan de la vue pour obtenir les points de (ssget) ?

 

grread retourne des coordonnées SCU et la liste de points requises par ssget sont aussi des coordonnées SCU mais si le SCU courant n'est pas parallèle à la vue la fenêtre de sélection ne sera pas rectangulaire.

Pour avoir une fenêtre rectangulaire il faut calculer les coordonnées des 4 sommets dans le SCU courant de façon à ce qu'ils affichent un rectangle dans la vue. Ceci nécessite de tradure le point de base et celui retourné par grread en "coordonnées vue" (trans pt 1 2), puis de calculer les 2 autres sommets pour avoir un rectangle en coordonnées vue. Les coordonnées SCU de ces deux points sont leur projection sur le plan du SCU courant, on les obtient avec ILP.

 

Si j'ai bien compris ce que tu veux faire, voici une fonction qui crée un jeu de sélection avec grread. Si l'utilisateur commence par sélectionner une entité avec un clic, la sélection s'arrête et le jeu de sélection ne contenant que cette entité est retourné. S'il commence par une fenêtre ou une capture la sélection continue jusqu'à validtion. Pendant la sélection, cliquer sur une entité sélectionnée, la dé sélectionne.

 

;; SelOneOrMore (gile)
;; Créé un jeu de sélection d'une ou plusieurs entités.
;; Si l'utilisateur commence par sélectionner une entité en 1 clic,
;; la sélection s'arrête, s'il commence par une fenêtre la sélection
;; continue jusqu'à la validation. cliquer sur une entité déjà sélectionner
;; la retire du jeu de sélection.
;;
;; Arguments
;; msg : un message ou nil (defaut "Choix des objets: ")
;; fltr : un filtre de sélection ou nil

(defun SelOneOrMore
      (msg fltr / *error* gr-sel-one gr-sel-more sel gsm ent ss n del)

 (defun *error* (msg)
   (or	(= msg "Fonction annulée")
(princ (strcat "\nErreur: " msg))
   )
   (if	(and sel (= (type sel) 'PICKSET))
     (repeat (setq n (sslength sel))
(redraw (ssname sel (setq n (1- n))) 4)
     )
   )
   (if	ss
     (repeat (setq n (sslength ss))
(redraw (ssname ss (setq n (1- n))) 4)
     )
   )
   (if	ss1
     (redraw (ssname ss1 0) 4)
   )
   (princ)
 )

 (defun gr-sel-one (fltr / loop gr pt ss1)
   (setq loop T)
   (while (and (setq gr (grread T 12 2)) (/= (car gr) 3) loop)
     (if ss1
(progn
  (setq ent (ssname ss1 0))
  (or (and ss (ssmemb ent ss)) (redraw ent 4))
  (setq ss1 nil)
)
     )
     (cond
((= (car gr) 5)
 (setq pt (cadr gr))
 (if (and (setq ss1 (ssget pt fltr)) (not del))
   (redraw (ssname ss1 0) 3)
   (setq del nil)
 )
)
((or (member gr '((2 13) (2 32)))
     (or (= (car gr) 11) (= (car gr) 25))
 )
 (if ss1
   (progn
     (redraw (ssname sel 0) 4)
     (setq ss1 nil)
   )
 )
 (setq loop nil
       pt   nil
 )
)
     )
   )
   (if	pt
     (cond
((setq ss1 (ssget pt fltr))
 (redraw (ssname ss1 0) 4)
 ss1
)
(pt)
     )
   )
 )

 (defun gr-sel-more (pt1ucs	/	  gr	    pt2ucs    pt3ucs
	      pt4ucs	pt1view	  pt2view   pt3view   pt4view
	      ssmode	result
	     )
   (while (and (setq gr (grread T 12 0)) (/= (car gr) 3))
     (redraw)
     (setq pt3ucs  (cadr gr)
    pt1view (trans pt1ucs 1 2)
    pt3view (trans pt3ucs 1 2)
    pt2view (list (car pt3view) (cadr pt1view) (caddr pt1view))
    pt4view (list (car pt1view) (cadr pt3view) (caddr pt3view))
    pt2ucs  (trans (ilp	pt2view
			(mapcar '+ pt2view '(0 0 1))
			(trans '(0 0 0) 1 2)
			(trans '(0 0 1) 1 2 T)
		   )
		   2
		   1
	    )
    pt4ucs  (trans (ilp	pt4view
			(mapcar '+ pt4view '(0 0 1))
			(trans '(0 0 0) 1 2)
			(trans '(0 0 1) 1 2 T)
		   )
		   2
		   1
	    )
    ssmode  (if	(		      "_CP"
	      "_WP"
	    )
     )
     (grvecs
(list (if (= ssmode "_CP")
	-255
	255
      )
      pt1ucs
      pt2ucs
      pt2ucs
      pt3ucs
      pt3ucs
      pt4ucs
      pt4ucs
      pt1ucs
)
     )
   )
   (redraw)
   (list ssmode pt1ucs pt2ucs pt3ucs pt4ucs)
 )

 (or msg (setq msg "\nChoix des objets: "))
 (princ msg)
 (setq sel (gr-sel-one fltr))
 (if (vl-consp sel)
   (progn
     (setq ss (ssadd))
     (princ "\nSpécifiez le coin opposé: ")
     (setq gsm (gr-sel-more sel))
     (if (setq sel (ssget (car gsm) (cdr gsm) fltr))
(repeat	(setq n (sslength sel))
  (setq ent (ssname sel (setq n (1- n))))
  (redraw ent 3)
  (ssadd ent ss)
)
     )
     (while (and (princ msg) (setq sel (gr-sel-one fltr)))
(if (vl-consp sel)
  (progn
    (princ "\nSpécifiez le coin opposé: ")
    (setq gsm (gr-sel-more sel))
    (if	(setq sel (ssget (car gsm) (cdr gsm) fltr))
      (repeat (setq n (sslength sel))
	(setq ent (ssname sel (setq n (1- n))))
	(redraw ent 3)
	(ssadd ent ss)
      )
    )
  )
  (progn
    (setq ent (ssname sel 0))
    (if	(ssmemb ent ss)
      (progn (redraw ent 4) (ssdel ent ss) (setq del T))
      (progn (redraw ent 3) (ssadd ent ss))
    )
  )
)
     )
   )
   (setq ss sel)
 )
 (repeat (setq n (sslength ss))
   (redraw (ssname ss (setq n (1- n))) 4)
 )
 ss
)

;; VXV
;; Retourne le produit scalaire (réel) de deux vecteurs
;;
;; Arguments : deux vecteurs

(defun vxv (v1 v2) (apply '+ (mapcar '* v1 v2)))

;; ILP Retourne le point d'intersection de la droite définie par p1 p2
;; et du plan défini par un point et sa normale.
;;
;; Arguments
;; p1 et p2 : les points définissant la droite dont on cherche l'intersection
;; org : un point queconque du plan d'intersection
;; nor : le vecteur normal du plan d'intersection

(defun ilp (p1 p2 org nor / scl)
 (if (and
(/= 0 (setq scl (vxv nor (mapcar '- p2 p1))))
(setq scl (/ (vxv nor (mapcar '- p1 org)) scl))
     )
   (mapcar (function (lambda (x1 x2) (+ (* scl (- x1 x2)) x1)))
    p1
    p2
   )
 )
)

 

Une fonction test

 

(defun c:test ()
 (sssetfirst
   nil
   (SelOneOrMore
     "\nSélectionnez les blocs: "
     '((0 . "INSERT"))
   )
 )
 (princ)
)

 

PS : je corrige le code donné plus haut

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Alors oui mais ça ne marche qu'avec les blocs chez moi, pas avec les entités... J'avoue que je n'ai pas cherché pourquoi, de toutes façons je vois le principe, et c'est vrai que ça évite un réacteur pour (command "SELECT")

 

Sinon pour la projection j'avais bien compris que c'était pour le traçage du rectangle de capture, mais j'avais cru que les points projetés partaient aussi dans (ssget).

 

Merci beaucoup pour tes efforts

Posté(e)

Salut,

 

Alors oui mais ça ne marche qu'avec les blocs chez moi, pas avec les entités...

 

La fonction SelOneOrMore accepte 2 arguments:

- le message qui s'affichera sur la ligne de commande

- un filtre de sélection : une liste comme celles utilisées avec ssget

 

Dans l'exemple, le filtre de sélection est '((0 . "INSERT")) c'est pour ça qu'on ne peut sélectionner que des références de blocs.

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Salut,

 

Merci beaucoup pour tes efforts

J'ai à peine modifié des routines que j'avais fait.

Je trouve quand même que c'est un peu lourd pour juste éviter un clic dans le vide (ou un clic gauche).

 

(defun c:toto (/ ss)
 (princ "\nSélectionnez un objet ou ")
 (setq ss (cond ((ssget "_+.:S:E")) ((ssget))))
 (sssetfirst nil ss)
 (princ)
)

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Toto utilise le renvoie (ssget) de façon très futée..

Mais ce n'est pas tout à fait ça : quand tu cliques dans le vide il faut recliquer ensuite pour faire une sélection multiple, or ce que je veux c'est que ton clic vide soit déjà le 1er point d'une sélection multiple.

A priori (je l'ai pas intégré encore) ça peut marcher avec ta fonction (SelOneOrMore), il suffit d'ajouter un test sur le 1er pointage :

(if (not(ssget "_S" pt0)) (SelOneOrMore pt0))

 

Je bricole une commande qui marche par défaut en sélection unique (selon un déroulement comparable à celui de _pedit par exemple). Eh bien dans ce cas je confirme que ce "raccourci" est diablement pratique, tu peux quasiment supprimer l'option M..[Edité le 14/5/2009 par krunch]

 

[Edité le 14/5/2009 par krunch]

Posté(e)

Mais ce n'est pas tout à fait ça : quand tu cliques dans le vide il faut recliquer ensuite pour faire une sélection multiple, or ce que je veux c'est que ton clic vide soit déjà le 1er point d'une sélection multiple.

 

C'est bien ce que je disais : "Je trouve quand même que c'est un peu lourd pour juste éviter un clic dans le vide (ou un clic gauche)."

 

ça peut marcher avec ta fonction (SelOneOrMore), il suffit d'ajouter un test sur le 1er pointage :

(if (not(ssget "_S" pt0)) (SelOneOrMore pt0))

 

Pas besoin d'ajouter de test SelOneOrMore fait exactement ce que tu décris et retourne le jeu de sélection.

Essaye (SelOneOrMore nil nil)

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Pas besoin d'ajouter de test SelOneOrMore fait exactement ce que tu décris et retourne le jeu de sélection.

Essaye (SelOneOrMore nil nil)

 

Il manque une parenthèse finale dans SelOneOrMore.

 

Sinon c'est tout à fait ça.. Et je confirme qu'à l'usage c'est un (petit) raccourci qui fait que tu ne te sers plus du tout de l'option M..

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité