Author Topic: Objects inside group [the most parent one]  (Read 2540 times)

0 Members and 1 Guest are viewing this topic.

Grrr1337

  • Swamp Rat
  • Posts: 812
Objects inside group [the most parent one]
« on: November 25, 2017, 02:23:20 PM »
Hey guys,

By providing a simple <ename> I'm trying to obtain a list of all <enames> that are located inside the most parent group.
So I'm thinking that a recursive function would be required to process every potential group for each entity.
Problem is that I got too confused with all that recursive processing and expecting the correct return at the same time.  :rolleyes2:

The simpliest start for the most inner group is:
Code: [Select]
; (e->GroupL (car (entsel)))
(defun e->GroupL ( e / grp L )
  (and
    (eq 'ENAME (type e))
    (setq grp (cdr (assoc 330 (entget e))))
    (foreach x (entget grp) (and (= 340 (car x)) (setq L (cons (cdr x) L))))
  )
  L
)

Say for a group that contains 2 circles, it would return 2 enames..
However if that group is a part of a larger group, say + 3 rectangles + another group of 2 polylines, it should return a list of these 7 enames.
(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)
vevo.bg

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Objects inside group [the most parent one]
« Reply #1 on: November 25, 2017, 03:16:02 PM »
Groups are not organised in a parent-child hierarchy. In your example only a single entity from the first group might be part of the second group. So the 'most parent group' does not always exist. Note that groups are stored in a dictionary in the namedobjdict and you can also use vla-* functions to work with them.

I can imagine this signature:
Code: [Select]
(MatchingGroupsGet <objLst> <modeEnum>) => list of group objects.
  objLst:
    List of graphical drawing objects.
  modeEnum:
    0: return all groups that contain one or more objects from objLst.
    1: return all groups that contain all objects from objLst.
    2: return all groups that exactly match objLst.
« Last Edit: November 25, 2017, 03:19:19 PM by roy_043 »

Grrr1337

  • Swamp Rat
  • Posts: 812
Re: Objects inside group [the most parent one]
« Reply #2 on: November 25, 2017, 04:41:04 PM »
Thanks Roy,
I was hoping for a recursive proccessing, that acts like a chain: entity->check_enames_inside_its_group_if_it_has_such.
Then perhaps I should try something with ssget, as my attempt was to substitute (ssget "_:S:L") with (entsel) because of the prompting.
The selection set return from (ssget "_:S:L") does obtain that "most parent group" - the enames inside of it.

I just don't like combining alert/princ prompts with ssget - (alert) pops-up are too annoyng, (princ/prompt) message is easy to miss or avoid.
(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)
vevo.bg

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1453
  • Marco
Re: Objects inside group [the most parent one]
« Reply #3 on: November 26, 2017, 03:53:38 AM »

Maybe this can help:
Code: [Select]
; Version 1.05 - 14/01/2006
; Credits: Tony Tanzillo
;
; Function: ALE_GetGroupNames
;
; Description:
;   returns a list of all the groups names of which EntNam is member
;
; Arguments:
;   EntNam: Entity name [ENAME]
;
; Example:
;   (ALE_GetGroupNames (entlast))
;
(defun ALE_GetGroupNames (EntNam / EntDat VlaObj OutLst)
  (if (setq EntDat (member '(102 . "{ACAD_REACTORS") (entget EntNam)))
    (while
      (and
        (setq EntDat (cdr EntDat))
        (eq (caar EntDat) 330)
        (eq
          (vla-get-ObjectName
            (setq VlaObj (vlax-ename->vla-object (cdar EntDat)))
          )
          "AcDbGroup"
        )
      )
      (if (equal (cadr EntDat) '(102 . "}")) (setq EntDat nil))
      (setq OutLst (cons (vla-get-Name VlaObj) OutLst))
    )
  )
)
(defun c:Test ( / ename result )
    (cond
        (   (and
                (setq ename (car (entsel)))
                (setq result (ALE_GetGroupNames ename))
            )
            (princ "\rEntity is a member of these groups:")
            (mapcar 'print result)
        )
        (   ename
            (princ "\rEntity is not a member of any group.")
        )
        (   (princ "\rNo entity selected.")   )
    )
    (princ)
)
; (ALE_GetGroupNames_Ss (ssget "_X"))
(defun ALE_GetGroupNames_Ss (SelSet / EntNam Countr NmsLst OutLst)
  (repeat (setq Countr (sslength SelSet))
    (setq Countr (1- Countr))
    (if (setq NmsLst (ALE_GetGroupNames (setq EntNam (ssname SelSet Countr))))
      (setq OutLst (cons (cons (DXF 0 (entget EntNam)) NmsLst) OutLst))
      (setq OutLst (cons (cons (DXF 0 (entget EntNam)) "- NONE -") OutLst))
    )
  )
  OutLst
)

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Objects inside group [the most parent one]
« Reply #4 on: November 26, 2017, 09:28:36 AM »
@Grrr1337:
The simplest way to accomplish you goal:
Code - Auto/Visual Lisp: [Select]
  1. (setq enm (car (entsel)))
  2. (command "_.select" enm "")
  3. (setq ss (ssget "_P"))

Grrr1337

  • Swamp Rat
  • Posts: 812
Re: Objects inside group [the most parent one]
« Reply #5 on: November 26, 2017, 12:12:23 PM »
Thank you guys!  :yay!:

@Marc
Thanks alot, (ALE_GetGroupNames) helped me.. so I wrapped a quick (command-call free) solution:
Code - Auto/Visual Lisp: [Select]
  1. ; (mapcar '(lambda (x) (and x (vla-highlight (vlax-ename->vla-object x) :vlax-true))) (e->ParentGroupL (car (entsel)))) ; visual test
  2. ; (e->ParentGroupL (car (entsel)))
  3. ; Returns a list of all enames grouped together within the provided ename, or just the ename if its not grouped
  4. (defun e->ParentGroupL ( e / GroupName->EnamesInsideOfIt _unique e r lens n )
  5.  
  6.   (defun GroupName->EnamesInsideOfIt ( nm / grp ) ; GroupName->EnamesInsideOfIt
  7.     (cond
  8.       ( (vl-catch-all-error-p (setq grp (vl-catch-all-apply 'dictsearch (list (cdr (assoc -1 (dictsearch (namedobjdict) "ACAD_GROUP"))) nm)))) )
  9.       ( (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= 340 (car x))) grp)) )
  10.     )
  11.   )
  12.  
  13.   (setq _unique (lambda ( L / r ) (foreach x L (or (member x r) (setq r (cons x r))) ) r))
  14.   (cond
  15.     ( (not (eq 'ENAME (type e))) nil)
  16.     ( (setq r (mapcar 'GroupName->EnamesInsideOfIt (ALE_GetGroupNames e))) ; list of ename lists, representing every group
  17.       ; (setq lens (mapcar 'length r)) (setq n (apply 'max lens)) (apply 'append (mapcar '(lambda (a b) (if (= n a) (list b))) lens r)) ; just forget about this
  18.       (_unique (apply 'append r)) ; Since same group can be grouped n times, flatten the list and extract each ename
  19.     )
  20.     ( e ) ; Just return the ename if its not within any groups
  21.   ); cond
  22. ); defun e->ParentGroupL


@Roy
Your suggestion works perfectly! I just wrapped it a bit:
Code - Auto/Visual Lisp: [Select]
  1. ; https://www.theswamp.org/index.php?topic=53668.0
  2. (setq e->MostParentGroupSS ; Roy
  3.   (lambda ( e )
  4.     (if (eq 'ENAME (type e))
  5.       (
  6.         (lambda ( c )
  7.           (setvar 'cmdecho 0)
  8.           (command "_.SELECT" e "")
  9.           (setvar 'cmdecho c)
  10.           (ssget "_P")
  11.         )
  12.         (getvar 'cmdecho)
  13.       )
  14.     )
  15.   ); lambda
  16. ); setq e->MostParentGroupSS

Although I try to avoid command-calls (and thats why I'm a dummy at calling commands within lisp),
I used Roy's suggestion in my main code, because its short and simple and I'm not using it within iterations (the command-call part).
Works as expected, thanks again!
(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)
vevo.bg

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1453
  • Marco
Re: Objects inside group [the most parent one]
« Reply #6 on: November 26, 2017, 12:27:08 PM »

Code: [Select]
(setq e->MostParentGroupSS ; Roy
  (lambda ( e )
    (if (eq 'ENAME (type e))
      (
        (lambda ( c )
          (setvar 'cmdecho 0)
          (command "_.SELECT" e "")
          (setvar 'cmdecho c)
          (ssget "_P")
        )
        (getvar 'cmdecho)
      )
    )
  ); lambda
)
Remember to verify PICKSTYLE = 1 (and HIGHLIGHT 0?)

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Objects inside group [the most parent one]
« Reply #7 on: November 26, 2017, 01:45:32 PM »
There is no need to check the PICKSTYLE if you use the _Select command. In all other cases you should.

Marc'Antonio Alessi

  • Swamp Rat
  • Posts: 1453
  • Marco
Re: Objects inside group [the most parent one]
« Reply #8 on: November 26, 2017, 03:41:27 PM »

There is no need to check the PICKSTYLE if you use the _Select command. In all other cases you should.
Do you test it?
Code: [Select]

Comando: (setvar 'PICKSTYLE 1)
1
Comando: (setq enm (car (entsel)))
Selezionare oggetto: <Nome entità: 2b64d550>
Comando: (command "_.select" enm "")
nil
Comando: (setq ss (ssget "_P"))
<Selection set: 18d>
Comando: (sslength ss)
1596  <<<<<<<<<<<<<<<<<<
Code: [Select]
Comando: (setvar 'PICKSTYLE 0)
0
Comando: (setq enm (car (entsel)))
Selezionare oggetto: <Nome entità: 2b64d550>
Comando: (command "_.select" enm "")
nil
Comando: (setq ss (ssget "_P"))
<Selection set: 1ae>
Comando: (sslength ss)
1  <<<<<<<<<<<<<<<<<<

Grrr1337

  • Swamp Rat
  • Posts: 812
Re: Objects inside group [the most parent one]
« Reply #9 on: November 26, 2017, 04:23:35 PM »
Thanks for pointing this out, Marc!
Then maybe an entsel wrapper would be better:
Code - Auto/Visual Lisp: [Select]
  1. ; https://www.theswamp.org/index.php?topic=53668.0
  2. ; Returns a selection set, containing selected enames within the most partent group, or just an ename - if there are no groups, else nil
  3. ; _$ (_PickMostParentGroup nil) -> <Selection set: 3c>
  4. ; (sslength (_PickMostParentGroup nil)) ; check
  5. (defun _PickMostParentGroup ( msg / *error* sv e r )
  6.  
  7.   (defun *error* ( m )
  8.     (and sv (mapcar '(lambda (x) (apply 'setvar x)) sv))
  9.     (and m (princ m)) (princ)
  10.   ); defun *error*
  11.  
  12.   (setq sv (apply 'append (mapcar '(lambda (x / v) (if (setq v (getvar (car x))) (progn (apply 'setvar x) (list (list (car x) v))))) '((pickstyle 1)(highlight 0)(cmdecho 0)(errno 0)))))
  13.  
  14.   (while (/= 52 (getvar 'errno)) (setq e (car (entsel (strcat "\n" (cond ( (eq 'STR (type msg)) msg) ("Select object <exit>: "))))))
  15.     (cond
  16.       ( (= 7 (getvar 'errno)) (setvar 'errno 0) ) ( (not e) )
  17.       ( (setq r ((lambda (x) (command "_.SELECT" x "") (ssget "_P")) e)) (setvar 'errno 52) )
  18.     ); cond
  19.   ); while
  20.   (*error* nil) r
  21. ); defun _PickMostParentGroup
(apply ''((a b c)(a b c))
  '(
    (( f L ) (apply 'strcat (f L)))
    (( L ) (if L (cons (chr (car L)) (f (cdr L)))))
    (72 101 108 108 111 32 87 111 114 108 100)
  )
)
vevo.bg

roy_043

  • Water Moccasin
  • Posts: 1895
  • BricsCAD 18
Re: Objects inside group [the most parent one]
« Reply #10 on: November 27, 2017, 03:55:53 AM »

There is no need to check the PICKSTYLE if you use the _Select command. In all other cases you should.
Do you test it?
Your test confirms my findings: The code respects the PCKSTYLE variable. IMO it should to avoid confusing the user.