Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Reply
Message 1 of 26
kulfi
903 Views, 25 Replies

List

I have a list Ent_list i want to arrange this entities list according to the x-axis value e.g for example which comes first than second and than third etc

 

list Ent_list = ((<Entity name: 7ffff60a380>) (<Entity name: 7ffff60a390>) (<Entity name: 7ffff60a3d0>) (<Entity name: 7ffff60a3e0>)

i have done it like this but this is giving me wrong result can u help please

 

(setq New_Ent_list (vl-sort Ent_list '(lambda (A B) (< (car (cdr (assoc 10 (entget (car (car Ent_list))))) )      (car (cdr (assoc 10 (entget (car (car Ent_list))))))))))

 

Thanks

Kulfi
Electronics Engineer

Pind Saudi Arabia



25 REPLIES 25
Message 2 of 26
martti.halminen
in reply to: kulfi

The are two problems with your approach.

 

First, your comparision function doesn't work, it should be comparing A and B instead of comparing the first item to itself.

Try something like  '(lambda (A B)(< (cadr (assoc 10 (entget (car A))))(cadr (assoc 10 (entget (car B))))))

 

The other potential problem is using VL-SORT: it drops duplicates, so if you have two items with the same X-coordinate, one is lost in sorting. You would need to use something based on vl-sort-i to avoid this.

 

For example:

(defun safer-sort (data comp-function key-function)
  ;; Sorting without dropping duplicates, uses key-function to dig out the value sorted upon.
  (mapcar
   (function (lambda (n) (nth n data)))
   (vl-sort-i (mapcar key-function data)
              comp-function)))

 You could also make things simpler using a list of entities, instead of a list of lists of entities.

 

(setq ents (apply 'append Ent_list))

 

(setq New_Ents  (safer-sort ents '< '(lambda (item)(cadr (assoc 10 (entget item))))))

 

--

Message 3 of 26
kulfi
in reply to: martti.halminen

OK thanks for the reply now let me tell u the exact problem i have a table of text and lines when i make crossing or windows on that table is it possible that all the entities coming in column and rows can be seprated in same Y and X order as the table is and than i can create a CSV file .

thanks

Kulfi
Electronics Engineer

Pind Saudi Arabia



Message 4 of 26
pbejse
in reply to: kulfi


@Anonymous wrote:

I have a list Ent_list i want to arrange this entities list according to the x-axis value e.g for example which comes first than second and than third etc

 

list Ent_list = ((<Entity name: 7ffff60a380>) (<Entity name: 7ffff60a390>) (<Entity name: 7ffff60a3d0>) (<Entity name: 7ffff60a3e0>)

i have done it like this but this is giving me wrong result can u help please

 

(setq New_Ent_list (vl-sort Ent_list '(lambda (A B) (< (car (cdr (assoc 10 (entget (car (car Ent_list))))) )      (car (cdr (assoc 10 (entget (car (car Ent_list))))))))))

 

Thanks


 

(setq New_Ent_list
       (vl-sort
  Ent_list
  '(lambda (A B)
     (<
       (car (cdr (assoc 10 (entget A)))
       )
       (car (cdr (assoc 10 (entget B)))
       )
     )
   )
       )
)

 

this will sort from left to right

 

 

Ooops. idint see your post there marti  🙂

Message 5 of 26
martti.halminen
in reply to: kulfi


@Anonymous wrote:

OK thanks for the reply now let me tell u the exact problem i have a table of text and lines when i make crossing or windows on that table is it possible that all the entities coming in column and rows can be seprated in same Y and X order as the table is and than i can create a CSV file .

thanks


If it is just text with no further structure, that should work: first sort on Y, split to groups of (almost) same Y value, and then sort each group (= line) on X.

 

You may have problems if some of the text is inside a block. Also, if you have an actual AutoCAD Table object, you could access that directly without searching and sorting.

 

You could also check whether the Data Extraction wizard does anything useful in this context.

 

--


 

Message 6 of 26
alanjt_
in reply to: martti.halminen

BTW, vl-sort will only remove duplicate integers, any other duplicates are sorted as desired.

Message 7 of 26
pbejse
in reply to: alanjt_

Nice to se you around this parts alanjt. 😉

 

Cool beans

 

Message 8 of 26
alanjt_
in reply to: pbejse

Yeah, I get around. 😛 Figured I'd poke my head in once in a while.

Message 9 of 26
Kent1Cooper
in reply to: kulfi


@Anonymous wrote:

I have a list Ent_list i want to arrange this entities list according to the x-axis value e.g for example which comes first than second and than third etc

 

....


Maybe you can use the BSSS routine in the BlockSSSort.lsp file [= Block Selection Set Sort], fairly early in this long thread:

http://forums.autodesk.com/t5/Visual-LISP-AutoLISP-and-General/Assigning-attributes-to-blocks-using-polyline-to-sequence-order/m-p/3146374/highlight/true#M298950

It's made for Blocks specifically, sorting by insertion point, and uses a selection set to start with rather than a list, but could be tailored.  It handles multiple columns and/or rows if needed, and sorts them in the order the User chooses, for instance:

 

(BSSS "T" "L")

 

sorts them into order with the Top row first, sorted from Left to right.

 

(BSSS "R" "B")

 

sorts them into order with the Right column first, sorted from Bottom to top.

 

If there's only one row, and you want them sorted left-to-right, you can use either (BSSS "T" "L") or (BSSS "B" "L").

 

It returns a sorted list of entity names.

Kent Cooper, AIA
Message 10 of 26
dgorsman
in reply to: pbejse

On larger lists, there may be repeated calls to (entget...) as elements bubble their way to the front of the list resulting in noticeable delays.  Might be worthwhile to (mapcar...) the (entget...) call into another list (of lists) and pass that through the (vl-sort '(lambda...)) function.  In fact, it might be even simpler to initially pull the X-coordinate out of each entity and assemble them into a list of dotted pairs, as (<entity> . #coordinate_value), and then pass that list to the sorting function.

----------------------------------
If you are going to fly by the seat of your pants, expect friction burns.
"I don't know" is the beginning of knowledge, not the end.


Message 11 of 26
alanjt_
in reply to: dgorsman

Good point.

 

eg.

(mapcar 'car
        (vl-sort (mapcar '(lambda (e) (list e (cadr (assoc 10 (entget e))))) lst)
                 '(lambda (a b) (< (cadr a) (cadr b)))
        )
)

 

Message 12 of 26
martti.halminen
in reply to: alanjt_


@alanjt_ wrote:

BTW, vl-sort will only remove duplicate integers, any other duplicates are sorted as desired.


Depends somewhat on what you desire. The documentation only says: Duplicate elements may be eliminated from the list.

 

$ (vl-sort  (list pi pi pi) '<)
(3.14159)

 

$ (vl-sort
   '(a d a c a b a a a a a a a a)
   '(lambda (s1 s2)
    (< (vl-symbol-name s1) (vl-symbol-name s2)) ) )

(A B C D)

 

--

Message 13 of 26
martti.halminen
in reply to: dgorsman


@dgorsman wrote:

On larger lists, there may be repeated calls to (entget...) as elements bubble their way to the front of the list resulting in noticeable delays.  Might be worthwhile to (mapcar...) the (entget...) call into another list (of lists) and pass that through the (vl-sort '(lambda...)) function.  In fact, it might be even simpler to initially pull the X-coordinate out of each entity and assemble them into a list of dotted pairs, as (<entity> . #coordinate_value), and then pass that list to the sorting function.


- the safer-sort function I wrote already handles this, if you put the entget stuff in the key-function argument.

 

--


 

Message 14 of 26
kulfi
in reply to: kulfi

OK i agree that i select all the text with same Y-Axis but it is not neccessary that all the text in one line have 100% same Y-Axis this is the serious issue where i am stuck can u tell me how can i solve this problem.

thanks

Kulfi
Electronics Engineer

Pind Saudi Arabia



Message 15 of 26
Kent1Cooper
in reply to: kulfi


@Anonymous wrote:

....i select all the text with same Y-Axis but it is not neccessary that all the text in one line have 100% same Y-Axis this is the serious issue where i am stuck can u tell me how can i solve this problem. ....


BSSS will do that.  Change "INSERT" to "TEXT" in the (ssget) filter at the top [and, I would suggest, change the command name to TSSS].  Ask it to sort with the left column first, even though the Text objects are in something more like a row [each Text entity will be its own "column"].  Sort each "column" either from top to bottom or from bottom to top, since that makes no difference to one-item columns:

 

(TSSS "L" "T")

or

(TSSS "L" "B")

 

Or, if they are reasonably close to the same Y coordinate, change the 1e-4 fuzz-factor argument in the (equal) function to something large enough to include all their Y values within its range.  Then you can do:
 

(TSSS "T" "L")

or

(TSSS "B" "L")

 

EDIT:

Try the attached, adjusted as suggested above [including changing variable names to be Text- rather than Block-related].  It doesn't have a larger fuzz factor, but for what you describe, you would use it sorting Left-column first.

 

To see the results [the Text content of each in sorted order], do this:

 

(foreach txt tlsort2 (print (cdr (assoc 1 (entget txt)))))

Kent Cooper, AIA
Message 16 of 26
martti.halminen
in reply to: kulfi


@Anonymous wrote:

OK i agree that i select all the text with same Y-Axis but it is not neccessary that all the text in one line have 100% same Y-Axis this is the serious issue where i am stuck can u tell me how can i solve this problem.

thanks



This depends on your data.

 If your table is regular, i.e. every field is populated so every row is the same length, you can just group the data by count: the first four items are row 1, next four are row 2 etc, if you have a four-column table.

 

Otherwise you'd have to group the items by ranges of coordinates: for example assuming 5 mm text height and 15 mm line spacing, anything with their Y-coordinate within 5 mm of the first item would be on the first row, and anything within 5 mm from the first rejected item is on the second row, and so on. (when operating on the list sorted by Y.)

- Of course, this breaks down if the text is too randomly placed.

 

I--

 

--

 

Message 17 of 26
kulfi
in reply to: Kent1Cooper

I do not understand ur coding Please can u explain ur parameters like Dir and First and explain in details .

thanks

Kulfi
Electronics Engineer

Pind Saudi Arabia



Message 18 of 26
alanjt_
in reply to: martti.halminen

Marti, I stand corrected. Thanks for the lesson.

Message 19 of 26
Kent1Cooper
in reply to: kulfi


@Anonymous wrote:

I do not understand ur coding Please can u explain ur parameters like Dir and First and explain in details .

thanks


The top of the file explains what the 'first' and 'dir' arguments are for, and how to use it.  T/B/L/R means the user must specify whether to start at the Top or Bottom or Left or Right.  In the 'first' argument, they specify whether they want the Top row first, or the Bottom row first, or the Left column first, or the Right column first.  In the 'dir' argument, they specify the direction of sorting within each row or column -- whether they want rows sorted from Left to right or from Right to left, or columns sorted from the Top down or from the Bottom up.  Top or Bottom 'first' arguments must be followed by Left or Right 'dir' arguments, and vice versa.

 

Try it on the attached demonstration drawing.  There are 6 pieces of Text, with contents "A" through "F", roughly in a row but not with insertion points at the same Y coordinate.  Their drawing order is not from left to right, either.  Do this:

 

(TSSS "L" "T")

 

which mean "sort the selected Text objects with the Left column first, followed by any further columns working to the right, and from the Top down in each column."  Select the Text objects by whatever means you choose.  The resulting tlsort2 variable will contain a list of their entity names in left-to-right order, that is with content in "A" through "F" order.  [You can see their content in sorted order with the (foreach) function in my previous post.]

 

It finds the "A" to be as far to the left as any objects are, regardless of whether it's the first drawn or the first selected, and sorts all objects with the same X coordinate as that into the first column, from top down.  But in this case that first column contains only the "A" Text, because there are no others with the same X coordinate.  Then it finds the "B" to be the next column over, etc.

 

In this case, with only one object per column, this would give the same result:

 

(TSSS "L" "B")

 

sorting each column from the Bottom up.  Try (TSSS "R" "B") to see that sorting from Right to left makes them come out in "F" through "A" order.

Kent Cooper, AIA
Message 20 of 26
kulfi
in reply to: martti.halminen

No, for the text randomly placed how can u say that it is 5mm apart or 6 mm etc u do not know because all the rows and columns may look straight but they are not.

thanks

Kulfi
Electronics Engineer

Pind Saudi Arabia



Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Customer Advisory Groups


Autodesk Design & Make Report