Author Topic: MLEADER arrow coordinates  (Read 8534 times)

0 Members and 1 Guest are viewing this topic.

CHulse

  • Swamp Rat
  • Posts: 504
MLEADER arrow coordinates
« on: March 21, 2019, 03:28:40 PM »
Could anyone share an example of how to access the arrowhead point location (coordinates) for mleaders?

Ultimately, I want to extract the leader coordinates and the text contents, but I don't see how to get to the arrowhead location.

Appreciate any help with this.
Thanks
Cary Hulse
Urban Forestry Manager
Wetland Studies and Solutions

Civil 3D 2020 & 2023

ronjonp

  • Needs a day job
  • Posts: 7527
Re: MLEADER arrow coordinates
« Reply #1 on: March 21, 2019, 04:18:13 PM »
Try something like this for some hints :)
Code: [Select]
(SETQ O (vlax-ename->vla-object (CAR (ENTSEL))))
(vlax-dump-Object O T)
(VLAX-INVOKE O 'GetLeaderLineVertices 0)

Windows 11 x64 - AutoCAD /C3D 2023

Custom Build PC

Lee Mac

  • Seagull
  • Posts: 12913
  • London, England
Re: MLEADER arrow coordinates
« Reply #2 on: March 21, 2019, 05:23:30 PM »
Here's another route -
Code - Auto/Visual Lisp: [Select]
  1. (if (setq s (ssget "_+.:E:S" '((0 . "MULTILEADER"))))
  2.     (cdr (assoc 10 (member '(304 . "LEADER_LINE{") (entget (ssname s 0)))))
  3. )

CHulse

  • Swamp Rat
  • Posts: 504
Re: MLEADER arrow coordinates
« Reply #3 on: March 22, 2019, 07:15:21 AM »
Thanks guys. I really appreciate the help.
Cary Hulse
Urban Forestry Manager
Wetland Studies and Solutions

Civil 3D 2020 & 2023

CHulse

  • Swamp Rat
  • Posts: 504
Re: MLEADER arrow coordinates
« Reply #4 on: April 11, 2019, 02:09:13 PM »
OK, so I'm a little confused with how this works.

Given 2 different drawings with mleaders-

this worked on one:
Code: [Select]
(vla-getleaderlinevertices obj 0)
but didn't work on the other.
This did:
Code: [Select]
(vla-getleaderlinevertices obj 1)

Help?
Cary Hulse
Urban Forestry Manager
Wetland Studies and Solutions

Civil 3D 2020 & 2023

Dlanor

  • Bull Frog
  • Posts: 263
Re: MLEADER arrow coordinates
« Reply #5 on: April 11, 2019, 04:45:52 PM »
Typing MLeader on the command lines gives you this :

Specify leader arrowhead location or [leader Landing first/Content first/Options] <Options>:

Default is to construct from arrowhead location to landing then content but you can also opt for Landing first then arrowhead then content

or

Content then construct the leader to the arrowhead (landing location is calculated from content location)

With the default option (vla-getleaderlinevertices obj 0) gets you the arrowhead. With the other options you have to use the (GetVertexCount) method to find out how many vertices there are, and the last one will be the arrowhead

Code - Auto/Visual Lisp: [Select]
  1. (vla-getvertexcount (vlax-ename->vla-object (car (entsel))) 0)

The 0 at the end is the index of the leader, as you can have multiple leaders to a single content. So on a 3 vertex leader the last vertex will be index 2 (indices are zero based)


 


Lee Mac

  • Seagull
  • Posts: 12913
  • London, England
Re: MLEADER arrow coordinates
« Reply #6 on: April 11, 2019, 04:51:22 PM »
Since a multileader can have multiple leader lines (by using the AIMLEADEREDITADD command), the leaderlineindex argument (the final integer argument) of the getleaderlinevertices method is a zero-based integer index corresponding to the leader line for which you wish to obtain the vertices.

Since leader lines are not re-indexed when a leader line is removed, if you have constructed a multileader with multiple leader lines, and then removed the first leader line constructed (using the AIMLEADEREDITREMOVE command), the remaining leader line will remain at index 1, and invoking the getleaderlinevertices method with a leaderlineindex argument of 0 will result in an error.

I should add that you can obtain a list of valid leader line indexes using the getleaderlineindexes method, and hence, a more robust method of obtaining the leader line vertices (for all leader lines associated with an multileader) could be the following:
Code - Auto/Visual Lisp: [Select]
  1. (defun mleaderlinevertices ( mlr )
  2.     (mapcar '(lambda ( x ) (vlax-invoke mlr 'getleaderlinevertices x)) (vlax-invoke mlr 'getleaderlineindexes 0))
  3. )
« Last Edit: April 11, 2019, 05:08:46 PM by Lee Mac »

CHulse

  • Swamp Rat
  • Posts: 504
Re: MLEADER arrow coordinates
« Reply #7 on: April 12, 2019, 01:16:05 PM »
Thanks Lee
using your hint, I've been playing around with this to get the first leader's coordinates:

Code - Auto/Visual Lisp: [Select]
  1. (setq idxa (car(vlax-safearray->list (vlax-variant-value (vla-GetLeaderLineIndexes obj 0))))
  2.          verts (vlax-safearray->list (vlax-variant-value (vla-getleaderlinevertices obj idxa))))
  3.  

This seems to work fine for most, but I still get an error with some leaders, saying "invalid index".


I'm not sure what to check. It seems to happen as you said, if a leader has been removed, and also in a file where the user apparently copy/pasted over and over from another dwg.
 
Is there a way to check for a valid leader that I'm missing?

« Last Edit: April 12, 2019, 01:21:29 PM by CHulse »
Cary Hulse
Urban Forestry Manager
Wetland Studies and Solutions

Civil 3D 2020 & 2023

Lee Mac

  • Seagull
  • Posts: 12913
  • London, England
Re: MLEADER arrow coordinates
« Reply #8 on: April 12, 2019, 01:48:02 PM »
Why not use the function I provided?

CHulse

  • Swamp Rat
  • Posts: 504
Re: MLEADER arrow coordinates
« Reply #9 on: April 12, 2019, 03:18:24 PM »
I did try that and had the same results, unless I wasn't applying it correctly.  I broke it down so I could follow it better. I still struggle with mapcar and lambda.


Here's my testing code:
Code - Auto/Visual Lisp: [Select]
  1. (while (setq en (ssname ss 0))
  2.                 (setq   obj      (vlax-ename->vla-object en) ;convert ename to vla object
  3.                            verts   (mapcar '(lambda ( x ) (vlax-invoke obj 'getleaderlinevertices x)) (vlax-invoke obj 'getleaderlineindexes 0))
  4.                 );_end setq
  5.  
  6.         (princ " verts: " )    
  7.         (princ verts)
  8.         (terpri )
  9.        
  10.         (ssdel en ss)  
  11. );_end while
  12.  
« Last Edit: April 12, 2019, 03:28:26 PM by CHulse »
Cary Hulse
Urban Forestry Manager
Wetland Studies and Solutions

Civil 3D 2020 & 2023

CHulse

  • Swamp Rat
  • Posts: 504
Re: MLEADER arrow coordinates
« Reply #10 on: April 12, 2019, 03:24:12 PM »
Here's an example of the mleaders I have. Some work fine and others give the error.
Cary Hulse
Urban Forestry Manager
Wetland Studies and Solutions

Civil 3D 2020 & 2023

Lee Mac

  • Seagull
  • Posts: 12913
  • London, England
Re: MLEADER arrow coordinates
« Reply #11 on: April 13, 2019, 02:41:08 PM »
Unless I've overlooked something, there would seem to be insufficient information exposed by the ActiveX properties & methods derived from a Multileader Object to tackle this purely through Visual LISP, for example: the methods getleaderlinevertices, getleaderlineindexes, & getleaderindex all require a leaderlineindex, but there does not appear to be a property or method which yields the available valid leader line indexes which may be supplied to these methods.

As such, I think this task may be easier to tackle through Vanilla AutoLISP since more information is exposed through the DXF data associated with a MULTILEADER entity.

To this end, consider the following function to return the vertices for all leaders associated with a given Multileader entity:
Code - Auto/Visual Lisp: [Select]
  1. (defun LM:mleadervertices ( ent )
  2.     (mapcar '(lambda ( x ) (massoc 10 x))
  3.         (massoc "LEADER_LINE{"
  4.             (cdr
  5.                 (assoc "LEADER{"
  6.                     (cdr
  7.                         (assoc "CONTEXT_DATA{"
  8.                             (parsedxfdata (entget ent))
  9.                         )
  10.                     )
  11.                 )
  12.             )
  13.         )
  14.     )
  15. )
  16. (defun massoc ( k l )
  17.     (mapcar 'cdr (vl-remove-if-not '(lambda ( x ) (= k (car x))) l))
  18. )
  19. (defun parsedxfdata ( l / foo )
  20.     (defun foo ( / x )
  21.         (setq x (car l)
  22.               l (cdr l)
  23.         )
  24.         (cond
  25.             (   (or (null x) (= "}" (cdr x)))
  26.                 nil
  27.             )
  28.             (   (and (= 'str (type (cdr x))) (wcmatch (cdr x) "*{*"))
  29.                 (cons (cons (cdr x) (foo)) (foo))
  30.             )
  31.             (   (cons x (foo)))
  32.         )
  33.     )
  34.     (foo)
  35. )

Here is a basic program to test the above:
Code - Auto/Visual Lisp: [Select]
  1. (defun c:test ( / c e )
  2.     (if
  3.         (and
  4.             (setq e (car (entsel "\nSelect mleader: ")))
  5.             (= "MULTILEADER" (cdr (assoc 0 (entget e))))
  6.             (setq c 1)
  7.         )
  8.         (foreach l (LM:mleadervertices e)
  9.             (foreach v l
  10.                 (entmake (list '(0 . "POINT") (cons 10 v) (cons 62 c)))
  11.             )
  12.             (setq c (1+ (rem c 255)))
  13.         )
  14.     )
  15. )

CHulse

  • Swamp Rat
  • Posts: 504
Re: MLEADER arrow coordinates
« Reply #12 on: April 13, 2019, 03:51:13 PM »
Thanks Lee
I'll give this a go on Monday. Much appreciated.
Cary Hulse
Urban Forestry Manager
Wetland Studies and Solutions

Civil 3D 2020 & 2023

Kycau

  • Mosquito
  • Posts: 2
Re: MLEADER arrow coordinates
« Reply #13 on: April 29, 2020, 07:28:59 AM »
I've read the topic a while ago, and experimented on my own, and came with this solution for myself:

Code: [Select]
(if (and (vl-catch-all-error-p (vl-catch-all-apply '(lambda (x) (vlax-invoke x 'getleaderlineindexes 1)) (list acadObj)))
    (= (vl-catch-all-error-message (vl-catch-all-apply '(lambda (x) (vlax-invoke x 'getleaderlineindexes 1)) (list acadObj)))
"AutoCAD.Application: Invalid index"))
       (setq sde_ml_indxlist (vlax-invoke acadObj 'getleaderlineindexes 0))
       (if (and (vl-catch-all-error-p (vl-catch-all-apply '(lambda (x) (vlax-invoke x 'getleaderlineindexes 0)) (list acadObj)))
   (= (vl-catch-all-error-message (vl-catch-all-apply '(lambda (x) (vlax-invoke x 'getleaderlineindexes 0)) (list acadObj)))
       "AutoCAD.Application: Invalid index"))
(setq sde_ml_indxlist (vlax-invoke acadObj 'getleaderlineindexes 1))
(setq sde_ml_indxlist (vl-sort (append (vlax-invoke acadObj 'getleaderlineindexes 0)
(vlax-invoke acadObj 'getleaderlineindexes 1)) '<))))

This way I can retrieve lineindexes that answer to either ”0”, or ”1”, or both at the same time (when mleader has leaders in both directions).

1st I check if mleader fails to deliver "1"-leaderlineindexes. If it fails, it means it can only deliver "0"-leaderlineindexes. It retrieves "0"-leaderlineindexes.
Than I check vice-versa.
If both these fail-verifications fail, this means that both deliveries "0" and "1" leaderlineindexes is possible.
So, as 3rd option, my routine retrieves all "0" and "1" leaderlineindexes.
It also sort's them in ascending order.

The only thing my routine doesn't handle properly, is the case when mleader doesn't have leaders at all... But well, I don't run my routing on such mleaders  :whistling:

Crank

  • Water Moccasin
  • Posts: 1503
Re: MLEADER arrow coordinates
« Reply #14 on: April 29, 2020, 08:47:48 AM »
It's also possible to use a block that looks like a leader with fields. Seems more reliable to me.
Vault Professional 2023     +     AEC Collection

CHulse

  • Swamp Rat
  • Posts: 504
Re: MLEADER arrow coordinates
« Reply #15 on: April 29, 2020, 11:13:05 AM »
In my case, I was given a dwg with mleaders representing tree locations and tag numbers (about 1000 of them) from a client. So I didn't have a choice.
I'll revisit this, but I hope I don't ever need to use it again :)
Cary Hulse
Urban Forestry Manager
Wetland Studies and Solutions

Civil 3D 2020 & 2023

dexus

  • Bull Frog
  • Posts: 206
Re: MLEADER arrow coordinates
« Reply #16 on: June 23, 2023, 05:44:09 AM »
I've read the topic a while ago, and experimented on my own, and came with this solution for myself:

Code: [Select]
(if (and (vl-catch-all-error-p (vl-catch-all-apply '(lambda (x) (vlax-invoke x 'getleaderlineindexes 1)) (list acadObj)))
    (= (vl-catch-all-error-message (vl-catch-all-apply '(lambda (x) (vlax-invoke x 'getleaderlineindexes 1)) (list acadObj)))
"AutoCAD.Application: Invalid index"))
       (setq sde_ml_indxlist (vlax-invoke acadObj 'getleaderlineindexes 0))
       (if (and (vl-catch-all-error-p (vl-catch-all-apply '(lambda (x) (vlax-invoke x 'getleaderlineindexes 0)) (list acadObj)))
   (= (vl-catch-all-error-message (vl-catch-all-apply '(lambda (x) (vlax-invoke x 'getleaderlineindexes 0)) (list acadObj)))
       "AutoCAD.Application: Invalid index"))
(setq sde_ml_indxlist (vlax-invoke acadObj 'getleaderlineindexes 1))
(setq sde_ml_indxlist (vl-sort (append (vlax-invoke acadObj 'getleaderlineindexes 0)
(vlax-invoke acadObj 'getleaderlineindexes 1)) '<))))

This way I can retrieve lineindexes that answer to either ”0”, or ”1”, or both at the same time (when mleader has leaders in both directions).

1st I check if mleader fails to deliver "1"-leaderlineindexes. If it fails, it means it can only deliver "0"-leaderlineindexes. It retrieves "0"-leaderlineindexes.
Than I check vice-versa.
If both these fail-verifications fail, this means that both deliveries "0" and "1" leaderlineindexes is possible.
So, as 3rd option, my routine retrieves all "0" and "1" leaderlineindexes.
It also sort's them in ascending order.

The only thing my routine doesn't handle properly, is the case when mleader doesn't have leaders at all... But well, I don't run my routing on such mleaders  :whistling:

Nice, this was exactly what I was looking for. Thank you!
I moved some things around and added a check for multileaders without any leaders.
Here is the result for anyone who tries to get all the leader information:

Code - Auto/Visual Lisp: [Select]
  1. (defun getLeaderIndexes (obj / _invalidIndex-p)
  2.   ; -----------------------------------
  3.   ; getLeaderIndexes
  4.   ; -----------------------------------
  5.   ; Returns a list of all valid indexes of a multileader
  6.   ; Input: vla-object of the multileader
  7.   ; Output: list of all valid indexes
  8.   ; -----------------------------------
  9.   ; Source:      https://www.theswamp.org/index.php?topic=55023.msg614986#msg614986
  10.   ; By:          Kycau (29-04-2020)
  11.   ; Modified by: dexus (23-06-2023)
  12.  
  13.   (defun _invalidIndex-p (obj in) ; Check if index is not valid
  14.     (and
  15.       (vl-catch-all-error-p (vl-catch-all-apply (function (lambda (x) (vlax-invoke x 'getleaderlineindexes in))) (list obj)))
  16.       (= (vl-catch-all-error-message (vl-catch-all-apply (function (lambda (x) (vlax-invoke x 'getLeaderLineIndexes in))) (list obj)))
  17.         "AutoCAD.Application: Invalid index"
  18.       )
  19.     )
  20.   )
  21.  
  22.   (cond
  23.     ((= (vla-get-leaderCount obj) 0) nil) ; No leaders
  24.     ((_invalidIndex-p obj 1) (vlax-invoke obj 'getLeaderLineIndexes 0)) ; Only leaders found in 0
  25.     ((_invalidIndex-p obj 0) (vlax-invoke obj 'getLeaderLineIndexes 1)) ; Only leaders found in 1
  26.     ((vl-sort (append (vlax-invoke obj 'getLeaderLineIndexes 0) (vlax-invoke obj 'getLeaderLineIndexes 1)) '<)) ; Both
  27.   )
  28. )