Help with entsel and/or nentsel

Help with entsel and/or nentsel

Strydaris2492
Advocate Advocate
1,182 Views
13 Replies
Message 1 of 14

Help with entsel and/or nentsel

Strydaris2492
Advocate
Advocate

I was hoping someone could help me out with this little snippet of code.

Essentially what I need it to do is this.

Select the text, mtext or attributed block. If its text/mtext then pick this point, if its a block with an attribute then get the attribute value, then get the insertion point of that block.

 

I know its something to do with how I am selecting the entity. When I use entsel, the selecting text portion works and the block doesnt. When I use nentsel the block portion works, but the text doesnt.

Can someone help me out here? 

(defun c:GetElevs (/)
    (vl-load-com)
  (LeeMac)
    (setq ent1 (car (nentsel "\nSelect first grade value: ")))
	(if ;selecting the first point... is it text or a block?
	  ;STARTING FIRST CONDITION TO CHECK FOR TEXT OR MTEXT
	   (wcmatch (cdr (assoc 0 (entget ent1))) "TEXT,MTEXT");condition check then do
	   ;(setvar "OSMODE" 32)
	   (setq ent1 (car (entsel ent1))
	     	 pt1 (Getpoint "\nSelect first grade point: ")
		 pt1 (list(car pt1)(cadr pt1) 0 )
		 hgt1 (car (LM:parsenumbers (cdr (assoc 1 (entget ent1)))))
		 hgt1 (LM:UnFormat hgt1 nil)
		 hgt1 (atof hgt1)
		 )
	  ;2nd Condition
	(progn
     	(setq hgt1 (LM:getattributevalue ent1 "ELEV" )
      	      ;hgt1 (atof hgt1)
	      )
	  (and
  		(= "ATTRIB" (cdr (assoc 0 (entget ent1))))
  		(setq attobj1 (vlax-ename->vla-object ent1))
  		(setq blkobj1 (cdr (assoc 330 (entget ent1))))
  		(setq attpt1 (vlax-get attobj1 'InsertionPoint))
  		(setq blkpt1 (cdr (assoc 10 (entget blkobj1))))
		(setq pt1 (trans blkpt1 0 1))
	    )
	); and
	  ;end 2nd condition
	  );end conditional statement
  

 

0 Likes
Accepted solutions (4)
1,183 Views
13 Replies
Replies (13)
Message 2 of 14

ВeekeeCZ
Consultant
Consultant

You can get a point from (entsel) and use it for (nentselp)

 

but... better post a sample dwg, the block specifically, and mark which point you want to get. 

0 Likes
Message 3 of 14

Strydaris2492
Advocate
Advocate

Its actually a very simple concept, I just don't know how to apply it yet. Still learning.

This routine is going to be the main selection function for other routines. I have about 4 routines that do the same selection method, but use the data from the points in different ways. I separated the selection part because I felt it was easier to use and update in one area, rather than in all 4 routines.

This routine works like this...

PT1 = Pick Grade Value(could be text, mtext or an attribute),if its text then pick the point, then repeat for PT2, entmake a line between the 2 points then do some math on pt1, hgt1 , pt2 & hgt2 in a different routine. Basically the ent2 section is a repeat of what I posted above and gives me pt2 and hgt2. I also use Lee Mac's GetAttribute function to retrieve the attribute value in the block.

I just tried using nentselp and that seems to grab the value for the text and the point for the block, but for some reason Lee's function cant extract the attribute value from the ENT1 or ENT2 entity.

 

0 Likes
Message 4 of 14

ВeekeeCZ
Consultant
Consultant
Accepted solution

Try this...

 

(defun c:getxyh ()
  
  (if (and (setq e (car (entsel "Pick elevation: ")))
	   (setq y (cdr (assoc 0 (entget e))))
	   )
    (cond ((= y "INSERT")
	   (setq p (reverse (cdr (reverse (cdr (assoc 10 (entget e))))))
	         h (atof (cdr (assoc 1 (entget (entnext e)))))))             ;; alt. (atof (getpropertyvalue e "ELEV"))
	         	  
	  ((= y "TEXT")
	   (if (setq p (getpoint "\nFirst grade point: "))
	     (setq p (reverse (Cdr (reverse p)))
		   h (atof (cdr (assoc 1 (entget e)))))))
	  
	  ((= y "MTEXT")
	   (if (setq p (getpoint "\nFirst grade point: "))
	     (setq p (reverse (cdr (reverse p)))
		   h (atof (getpropertyvalue e "Text")))))
	  
	  ))
  
  (append p (list h))
  )

 

0 Likes
Message 5 of 14

Strydaris2492
Advocate
Advocate

Oh man. This is why I come here for help! lol

Ok let me see if I am reading the lisp right.

P and H are my pt1 and hgt1 replacements. E is my ent1 replacement

You are using IF E AND Y as a check, then running the conditions on that check.

Y is getting the ( 0 . "whatever") from E

Then looking for the cond statement that it corresponds to and running through that.

Only thing I am not getting is the assoc 1 (entget (entnext E) part. This is getting the attribute value, correct. Is it the dxf codes? ( 1 . "value")? If so, how do you look at those. I have a lisp called getdxf and it doesnt show them in the returned info.

 

Anyways, this seems to work great. Just need to add in the trans and repeat it for a second point and I think it will work.

0 Likes
Message 6 of 14

ВeekeeCZ
Consultant
Consultant

HERE is a list of entities and their DXF code lists.

HERE is something about attributes, why att ename is next to reference ename.

 

Possibly the simplest way to get att value from block reference ename is (getpropertyvalue ref-ename tag). Presumably, you know the tag name.

0 Likes
Message 7 of 14

Strydaris2492
Advocate
Advocate

Hey @ВeekeeCZ BeekeeCZ,

 

I was wondering if you could help me out once more with this.

This has been working great for me and a few others in my office for selecting the info we need.

The only issue or complaint I am getting is when the user misclicks the ent and returns nil error.

 

Is there a way to add a while loop to this to loop back for the selection if ent1 returns nil or misclicked?

  (if (and (setq ent1 (car (entsel "\nPick first elevation value: ")))
	   (setq y1 (cdr (assoc 0 (entget ent1))))
	   )
    (cond ((= y1 "INSERT")
	   (setq pt1 (trans (reverse (cdr (reverse (cdr (assoc 10 (entget ent1)))))) 0 1)
	         hgt1 (atof (cdr (assoc 1 (entget (entnext ent1)))))))             ;; alt. (atof (getpropertyvalue e "ELEV"))
	         	  
	  ((= y1 "TEXT")
   	   (setvar "OSMODE" 32)
	   (if (setq pt1 (getpoint "\nFirst grade point: "))
	     (setq pt1 (reverse (Cdr (reverse pt1)))
		   hgt1 (atof (cdr (assoc 1 (entget ent1)))))))
	  
	  ((= y1 "MTEXT")
	   (setvar "OSMODE" 32)
	   (if (setq pt1 (getpoint "\nFirst grade point: "))
	     (setq pt1 (reverse (cdr (reverse pt1)))
		   hgt1 (atof (getpropertyvalue ent1 "Text")))))
	  )
     );end if

I havent done this sort of thing before.

From reading around, I thought that I could simply just change the code at the beginning where it selects sets the ent1 like I have below.

  (if (while (not (and (setq ent1 (car (entsel "\nPick first elevation value: ")))
		       (setq y1 (cdr (assoc 0 (entget ent1))))
		       )
		  )
	 (progn
	    	(alert "\nMissed Grade value. Select again.")
	 	(prompt "\nMissed Grade value. Select again.")
	    )
	 )

This doesnt seem to fully work properly though. It does loop if the text object is not selected, but it doesnt seem to want to create the tmpln between the 2 points.

Any ideas?

Here is the full code below. I changed it to be a regular function for testing. I usually have it as a Sub Function because I use this code for selecting on multiple Lisps.

(defun c:getelevs (/ y1 y2 exv)
(vl-load-com)   
      ; (defun *error* ( msg )
;	(if tmpln (entdel tmpln))
;      	(if os (setvar 'osmode os))
;       (if cl (setvar 'clayer cl))
;	(vla-EndUndoMark adoc)
;	(if (not (wcmatch (strcase msg T) "*break*,*cancel*,*exit*"))
;	    (princ (strcat "Error: " msg))
;	    )
;	)

  
  (if (while (not (and (setq ent1 (car (entsel "\nPick first elevation value: ")))
		       (setq y1 (cdr (assoc 0 (entget ent1))))
		       )
		  )
	 (progn
	    	(alert "\nMissed Grade value. Select again.")
	 	(prompt "\nMissed Grade value. Select again.")
	    )
	 )
    (cond ((= y1 "INSERT")
	   (setq pt1 (trans (reverse (cdr (reverse (cdr (assoc 10 (entget ent1)))))) 0 1)
	         hgt1 (atof (cdr (assoc 1 (entget (entnext ent1)))))))             ;; alt. (atof (getpropertyvalue e "ELEV"))
	         	  
	  ((= y1 "TEXT")
   	   (setvar "OSMODE" 32)
	   (if (setq pt1 (getpoint "\nFirst grade point: "))
	     (setq pt1 (reverse (Cdr (reverse pt1)))
		   hgt1 (atof (cdr (assoc 1 (entget ent1)))))))
	  
	  ((= y1 "MTEXT")
	   (setvar "OSMODE" 32)
	   (if (setq pt1 (getpoint "\nFirst grade point: "))
	     (setq pt1 (reverse (cdr (reverse pt1)))
		   hgt1 (atof (getpropertyvalue ent1 "Text")))))
	  )
     );end if
  
  (append pt1 (list hgt1))
;Get Second value and point
  (if (while (not (and (setq ent2 (car (entsel "\nPick second elevation value: ")))
		       (setq y2 (cdr (assoc 0 (entget ent2))))
		       )
		  )
	 (progn
	    	(alert "\nMissed Grade value. Select again.")
	 	(prompt "\nMissed Grade value. Select again.")
	    )
	 )
    (cond ((= y2 "INSERT")
	   (setq pt2 (trans (reverse (cdr (reverse (cdr (assoc 10 (entget ent2)))))) 0 1)
	         hgt2 (atof (cdr (assoc 1 (entget (entnext ent2)))))))             ;; alt. (atof (getpropertyvalue e "ELEV"))
	         	  
	  ((= y2 "TEXT")
	   (if (setq pt2 (getpoint "\nSecond grade point: "))
	     (setq pt2 (reverse (Cdr (reverse pt2)))
		   hgt2 (atof (cdr (assoc 1 (entget ent2)))))))
	  
	  ((= y2 "MTEXT")
	   (if (setq pt2 (getpoint "\nSecond grade point: "))
	     (setq pt2 (reverse (cdr (reverse pt2)))
		   hgt2 (atof (getpropertyvalue ent2 "Text")))))
	   ))
  
  (append pt2 (list hgt2))
  	(setq exv (trans (list 0 0 1) 1 0 T)
	      tmpln (entmakex (list
				'(0 . "LINE")
			       (cons 8 lay1)
			       (cons 10 (trans pt1 1 0))
			       (cons 11 (trans pt2 1 0))
			       (cons 210 exv)
			       );list
			     );entmakex
	      );setq
  );end getelevs

 

0 Likes
Message 8 of 14

Strydaris2492
Advocate
Advocate
Accepted solution

@ВeekeeCZ 

I figured it out.

I found a little snippet of code that allows me to do the while loop at the entsel side.

I added this Sub Function to the file.

(defun _entsel (msg / p r)
  (setvar "ErrNo" 0)
  (while (not (cond ((and (null (setq p (entsel (strcat "\n" msg)))) (/= 52 (getvar 'errno)))
		     (prompt "\nMissed grade value, try again...")
		     (alert "\nMissed grade value, try again...")
		    )
		    ((null p) t)
		    ((setq r p))
	      )
	 )
  )
  r
)
;; (_entsel "Pick something: ")

 

The only difference in the original code that you helped out (or rewrote for me) is this....

  (if (and (setq ent2 (car (_entsel "\nPick second elevation value: ")))
	   (setq y2 (cdr (assoc 0 (entget ent2))))
	   )

The only difference is instead of using entsel, I now use _entsel.

Everything now works beautifully again and has misclick handling.

Only thing I have to decide is whether to use a prompt to tell people they suck at clicking on things or use an alert. lol

0 Likes
Message 9 of 14

ronjonp
Advisor
Advisor
Accepted solution

Thought that function was familiar 🙂

0 Likes
Message 10 of 14

Strydaris2492
Advocate
Advocate

@ronjonp 

LOL. I stalk your work on the ALL the LISP forums.

I was going to give you credit, but I closed the browser after I copied it over and forgot exactly who it was that I copied it from. Its been a LONG week.

Thanks @ronjonp, without people like you & @ВeekeeCZ , I would be stuck figuring things out for longer than I want to.

Your function worked beautifully. I even just modified it to use nentsel for a different function I have and that worked great too.

0 Likes
Message 11 of 14

ronjonp
Advisor
Advisor

@Strydaris2492 I did not create that function. I also stand on the shoulders of giants sometimes. 😁

0 Likes
Message 12 of 14

Strydaris2492
Advocate
Advocate

@ronjonp we all need to learn from someone.

Whether you created that function or not, simply posting it solved a huge headache for me at my office.

Too many people there always asking "Why didnt it work?" and since I use this getelevs function for most of the other LISP I have, I think I will leave the ALERT message up just to make sure they KNOW they failed at clicking the proper text object. Maybe even add a YOU FAILED! in the alert for good measure!

0 Likes
Message 13 of 14

ВeekeeCZ
Consultant
Consultant
Accepted solution

This so much reminds me... elevation interpolation was the one I learned LISP on. This input function I re-wrote 3 times to find an efficient workflow. This version of yours was the first one. The second one was to pre-draw the text alignment point and possibly <accept>. The final version accepted an alignment point by default with possible backward revision. 

 

I would not recommend using an ALERT. It requires a silly extra step to dismiss. You should rather use a visual confirmation that the selection was correct and accepted - possibly draw a temporary point, highlight accepted elevation... Btw, how do you like... YOU FAILED! with this way of thinking. 

 

I see that you use a temp LINE... I would rather use XLINE so the user can pick a point beyond the base points.

0 Likes
Message 14 of 14

Strydaris2492
Advocate
Advocate

Hi @ВeekeeCZ ,

 

Yes this sub function is being used for elevation interpolation, slopes between 2 points, top of berm calculations, rear apron calculations and a few more. Seeing as its all math based on the 2 points selected using this function, it was easy to create the added LISPs that I needed to make everything we needed in the office.

 

I took your advice and added in a REDRAW ent 3 then REDRAW ent 4 for the selections. This is much better than my proposed YOU FAILED alert. Although the YOU FAILED was a lot funnier.

 

I thought about using XLINE to extend the line past the 2 selected points. The only issue with that is that my interpolation calculations are only based on the slope being the same. If the slope changes, as it can often do beyond the initial selected base points, it will give the incorrect interpolated value. This is why I chose to just use a line between the base points. This wont stop users from selecting beyond the base points, but it will show them the intended location to insert the interpolated value.

 

As always, thank you for your help and thoughts on how I can improve things.

Its very much appreciated.

0 Likes