Structure of Model Space

Structure of Model Space

Anonymous
Not applicable
1,496 Views
8 Replies
Message 1 of 9

Structure of Model Space

Anonymous
Not applicable

Background: I am attempting to loop through all entities in the model space. While looping through I will be adding and deleting entities. I need to keep looping through the entities in the original drawings and not loop through entities I just added, as well as not missing any of the original entities. I am treating the model space as a list, and accessing elements by index. Currently I am grabbing each element by index in reversed order, assuming that added elements will be pushed on the end of the list.

 

Question: How is the model space structured? Is it proper to treat the model space as a list or queue? How can I access all the original elements while adding and deleting elements in the processes of looping through the model space? 

 

Thanks in advance!

0 Likes
Accepted solutions (1)
1,497 Views
8 Replies
Replies (8)
Message 2 of 9

lando7189
Advocate
Advocate

Do it in 2 loops.  First, loop through and put all of the entities into an array or a collection.  Then, loop that array or collection and do your changes.

0 Likes
Message 3 of 9

john.uhden
Mentor
Mentor

You could use lists, but you might be better off using selection sets.

 

F'rinstance, you could start with (setq MSS (ssget "x" '((410 . "Model"))))

If you want to keep track of things you have added, then

(setq MySS (ssadd (entlast) MySS))

But watch out.  Deleting (erasing)  entities from MSS does not reduce the (sslength MSS) because if you erased an entity it can be unerased using entdel.  Each erasure (of an entity named e) would have to be followed by  (ssdel e MSS).

So maybe you would be better off with lists as you can add to them (cons) and delete from them (vl-remove).

Anyway, don't count on a selection set being in order of the entity creation.

John F. Uhden

Message 4 of 9

CodeDing
Advisor
Advisor

@Anonymous,

 

Why not just...

 

(defun c:EVERYTHING ( / ss ent)
;;Stores everything in current database
(setq ss (ssget "_X"))
;;loop through everything
(repeat (sslength ss)
;;get entity name
(setq ent (ssname ss 0))

;;DO STUFF WITH ENTITY...

;;delete entity from ss when finished (ssdel ent ss) );repeat (princ);finish quietly );defun

?

not tested

 

Best,

~DD

0 Likes
Message 5 of 9

lando7189
Advocate
Advocate

Ugh... my head was in VB.... the (ssget "X") route is the way to go as John stated.

0 Likes
Message 6 of 9

doaiena
Collaborator
Collaborator

As @john.uhden said, (setq MSS (ssget "X" '((410 . "Model")))) will select the objects in model space. Then i would suggest you add a marker to track all new entities and add them to a new selection set later /if needed/. To keep things simple, don't add your newly created entities in the same selection set you are working on.

 

;select everything in model space
(setq MSS (ssget "x" '((410 . "Model"))))

;keep track of the last entity
(setq lastEnt (entlast))

(repeat (sslength MSS)
;do stuff here with the old entities in model space
;and add new ones if you wish
)

;create an empty selection set for your newly created entities
(setq NSS (ssadd))

;add all the newly created entities to the NSS selection set
(while (setq lastEnt (entnext lastEnt))
(ssadd lastEnt NSS))

Later if you wish you could easily loop through the newly created entities only, without touching the ones that were already in the drawing.

PS:

When you delete an entity, make sure to remove it from the original selection set. 

(ssdel ent MSS)

0 Likes
Message 7 of 9

john.uhden
Mentor
Mentor

Be carefull there.

If the last entity were a block with attributes, or a heavy or 3D polyline, then

(while (setq lastEnt (entnext lastEnt))
might get you only an attribute or vertex

Use this function instead of just plain entlast.

(defun @entlast (/ ent1 ent2)
   (setq ent1 (entlast))
   (while (setq ent2 (entnext ent1))
       (setq ent1 ent2)
   )
   ent1
)

 Fear not.  The @ character is just my habitual way of naming functions.

John F. Uhden

Message 8 of 9

Anonymous
Not applicable

The way I am solving this issue is adjusting the index according to how many entities will get added to the model space. This will cause some overlap, but I think it will be more efficient than looping over the model space multiple times. For example, if while looping through, I explode a block with 5 attributes, then I will adjust the index of my next call to the model space by 5. This means I may call 5 entities for the second time as a worst case scenario, but it will ensure that I am not skipping any entities. 

 

My original question still goes unanswered, however. I assume that an object added to the model space will go in some type of order, not just in a random place as it may seem. If for instance I add a circle to the model space, it doesn't appear to be placed at the beginning or end of the model space, but somewhere in the middle. How is the model space structured in this context? If I add an entity to the model space, is there a way of knowing where it will be in the list of entities?

0 Likes
Message 9 of 9

john.uhden
Mentor
Mentor
Accepted solution

Regarding the order structure, AutoCAD keeps entities on the order of their creation, but also identifies each with a unique handle (dxf code 5) which is in hexadecimal format.

From my experience, I have never trusted any (ssget) method to create a selection set in their order of creation, so it's sort of like Alex Haley's story Roots where to get the history in order, you have to start at the beginning.

You can do that by using (entnext ...).

(entnext) returns the first graphical entity in the drawing database.

(entnext e) returns the next entity after e in the drawing database.

So, you could create a list of the entities in order using a function like this:

(defun @elist ( / e elist)
  (while (setq e (if e (entnext e)(entnext)))
    (setq elist (cons e elist))
  )
  (reverse elist)
)
But, (entnext) returns subentities too, like attributes and heavy or 3D polyline vertices, as in...
Line
Text
Circle
3DPoly, vertex, vertex, vertex, Seqend
Insert, Attrib, Attrib, Attrib, Seqend
etc.

So, if you have thousands of entities in a drawing, using @entnext will probably take a long while.
**** BTW, I don't know how to get out of this code formatting. Oh, well.

Now then, you might think of ordering entities by their handle.
There are hex->integer functions around here somewhere (I think @dbroad's contribution
is one of the best). But watch your @$$ there because if you copy entities from another
drawing, AutoCAD tries to preserve their handles and there is no guarantee that they will
result in a numerical order of creation.

So, it seems (even though someone much smarter than myself will correct me) that
@@elist might be your best bet.

BUT, rather than creating a list, it may be faster to create a selection set, as in:
(defun @ssall ( / e ss)
(setq ss (ssadd))
(while (setq e (if e (entnext e)(entnext)))
(ssadd e ss)
)
)
And I think that subentities are excluded individually because they are children of their parents.
BUT, I haven't tested any of this, and I'm holding up dinner. :/ 

 

John F. Uhden

0 Likes