Jump to content

while+vl-some Double loop is slow


ekko

Recommended Posts

The code and test graph are below

 

Hello everyone, about finding parallel lines in the entity list, I wrote a piece of code myself that can implement the function. When the number of entities reaches 929, it runs very badly (run time 17.6 seconds)
while + vl-some 17.6 seconds
while + foreach 30.15 seconds
while + vl-remove-if 29.42 seconds

The above is the data I tested, apparently my choice is now while + vl-some . I'm a novice, I hope to get the help of the master to make it faster, thank you

Edited by ekko
Link to comment
Share on other sites

Just a guess, you have a while loop and then another loop, or 929 loops and each loop is doing 929 operations, 863,000 calculations.... might be why it is slowing down?

Link to comment
Share on other sites

31 minutes ago, Steven P said:

Just a guess, you have a while loop and then another loop, or 929 loops and each loop is doing 929 operations, 863,000 calculations.... might be why it is slowing down?

In fact, there are not so many loops. Even if I use while+foreach, I will loop about 17,000 times. However, the number of loops with while+vl-some should be less, because vl-some seems to stop searching when the condition is met. It should be the reason why my experiment above is faster. Well, my purpose now is to find a better way, a way to make it faster

Link to comment
Share on other sites

34 minutes ago, exceed said:

I haven't tested, but If there are only simple straight lines, Create a degree list and entityname list. 

And the degree list is extracted using Lee Mac's LM:ListDupes. ( http://www.lee-mac.com/uniqueduplicate.html )

If there is a duplicate degree in the degree list, the entity name is extracted with the index no.

Thank you for your suggestion, my bro. Before writing the code, I read it and borrowed the method of lee mac. Now the running speed cannot meet my requirements, but writing the above code is already the limit of my current technology. . I thought that after vl-some satisfies the condition, then delete x directly. I think this will reduce the number in the table and the number of loops. The natural speed is fast, the problem is that I don't know how to do it.

Link to comment
Share on other sites

Just for checking and seeing what it happening, could you post the bit of code that comes before parallel and creates lst - saves us 20 minutes making that up to see what is happening.

Link to comment
Share on other sites

23 hours ago, Steven P said:

Just for checking and seeing what it happening, could you post the bit of code that comes before parallel and creates lst - saves us 20 minutes making that up to see what is happening.

 

 

I have uploaded the test chart and test code, this is only part of the code, it can't see the speed in the test chart, when it runs in the complete code, the speed is very slow, I am sure that this part causes the running speed to change slow, so I'm looking for ways to make it run faster

Parallel.dwg

Edited by ekko
Link to comment
Share on other sites

You should run the calculations on the list building a new list with the answers. This way your only doing the calculations once and in the loops your only pulling values.

 

(foreach e lst
  (setq l (cons (list e ang len) l))
)
  

;;;ent angle
(defun ang (e)
  (vlax-get-property (EtoO e) 'angle)
)

 

Would turn

(<Entity name: 4ecbaf20> <Entity name: 4ecba4e0>)

into

((<Entity name: 4ecbaf20> 30 1.26) (<Entity name: 4ecba4e0>  60 2.33))

 

if the angles are the same then they are parallel

(if (and (=\ (cadr x) (cadr e)) (equal (caddr x) (caddr e) 1))

(if (and (=\ (30) (60)) (equal (1.26) (2.33) 1))
t

 

Edited by mhupp
  • Thanks 1
Link to comment
Share on other sites

23 minutes ago, mhupp said:

You should run the calculations on the list building a new list with the answers. This way your only doing the calculations once and in the loops your only pulling values.

 

(foreach e lst
  (setq l (cons (list e ang len) l))
)
  

;;;ent angle
(defun ang (e)
  (vlax-get-property (EtoO e) 'angle)
)

 

Would turn

(<Entity name: 4ecbaf20> <Entity name: 4ecba4e0>)

into

((<Entity name: 4ecbaf20> 30 1.26) (<Entity name: 4ecba4e0>  60 2.33))

 

if the angles are the same then they are parallel

(if (and (=\ (cadr x) (cadr e)) (equal (caddr x) (caddr e) 1))

(if (and (=\ (60) (30)) (equal (1.26) (2.33) 1))
t

 

(vlax-get-property (EtoO e) 'angle)  function not valid for lwpolyline,In addition, I tested, two parallel lines drawn in the same direction, their angles are not the same, do I need to calculate?

Link to comment
Share on other sites

 

A value of 180 degrees or more in the expression for parallelism is equivalent to -180 degrees.

 

It is easily solved by putting a single if statement in front of it. In this process you will be able to purge decimal errors by rounding off.

 

because lwpolyline can have multiple vertices, so check whether the object is a line or an lwpolyline, and if it is an lwpolyline, check if it has only two points, and if both conditions are passed, calculate the angle and put it in the list.

 

An easy way to solve this is to explode and treat them all as lines.

Edited by exceed
  • Thanks 1
Link to comment
Share on other sites

8 minutes ago, exceed said:

A value of 180 degrees or more in the expression for parallelism is equivalent to -180 degrees.

 

It is easily solved by putting a single if statement in front of it. In this process you will be able to purge decimal errors by rounding off.

 

An lw polyline can have multiple vertices, so check whether the object is a line or an lwpolyline, and if it is an lwpolyline, check if it has only two points, and if both conditions are passed, calculate the angle and put it in the list. An easy way to solve this is to explode and treat them all as lines.

A value of 180 degrees or more in the expression for parallelism is equivalent to -180 degrees.

 

It is easily solved by putting a single if statement in front of it. In this process you will be able to purge decimal errors by rounding off.

 

because lwpolyline can have multiple vertices, so check whether the object is a line or an lwpolyline, and if it is an lwpolyline, check if it has only two points, and if both conditions are passed, calculate the angle and put it in the list.

 

An easy way to solve this is to explode and treat them all as lines.

OK, thanks

Link to comment
Share on other sites

@ekko

Are you trying to make a selection set of equal length and angle based on a pick? I ran your code and all it does is highlight your entire test drawing.

Link to comment
Share on other sites

21 hours ago, ronjonp said:

@ekko

Are you trying to make a selection set of equal length and angle based on a pick? I ran your code and all it does is highlight your entire test drawing.

 

 

(foreach x parlst (mapcar '(lambda (y) (redraw y 3)) x) )  

Good evening, you may not have looked at the code carefully, the program highlights the line that is parallel and has the same length, it is stored in the parlst list

Forgive me, the graphs in the test chart are all satisfied parallel lines, this may mislead you into thinking that only the selected line is highlighted

 

Edited by ekko
Link to comment
Share on other sites

@ekko I did look at your code I'm just confused as to what you're trying to do. I would expect the result to look something like this:

image.png.dcb84ef9fa80958b6a4b65a121703e28.png

or this

image.png.92c6fdc67ffeb845407bdcc5142e7af3.png

Edited by ronjonp
Link to comment
Share on other sites

7 minutes ago, ronjonp said:

@ekko i did look at your code I'm just confused as to what you're trying to do. I would expect something like this:

image.png.dcb84ef9fa80958b6a4b65a121703e28.png

I'm sorry for not stating the requirement, first of all finding parallel lines is only part of the function of the program. The problem now is that when the amount of data is large, this part causes the program to run very slowly. I hope to be optimized to improve the running speed of the program

 

I think, my program loops on the entity table 5 times, which is the key to affecting the running speed of which SStoE 2 times, while 1 time vl-some 1 time (vl-remove) 1 time

Edited by ekko
Link to comment
Share on other sites

Do a presort like so to speed this up. This took ~5s to process 130,000 lines.

(defun c:foo (/ a b c e f n r s)
  ;; RJP » 2022-04-14
  ;; Groups a list of lists of lines that have similar angles and lengths
  (setq f 1e-1)
  (cond
    ((setq s (ssget '((0 . "LINE"))))
     (setq s (mapcar '(lambda (e)
			(setq a (vlax-curve-getstartpoint e))
			(setq b (vlax-curve-getendpoint e))
			(list (rem (angle a b) pi) (distance a b) e)
		      )
		     (vl-remove-if 'listp (mapcar 'cadr (ssnamex s)))
	     )
     )
     ;; Presort by sum of angle and length
     (setq s (vl-sort s (function (lambda (r j) (< (+ (cadr r) (car r)) (+ (cadr j) (car j)))))))
     ;; While we have a list
     (while (setq a (car s))
       ;; Remove first item
       (setq s (cdr s))
       ;; Reset temp list
       (setq c nil)
       ;; Add first item to temp list 'c'
       (setq c (cons a c))
       ;; While we have a list 's' and the angle and length is 'equal', compile temp list 'c'
       (while (and s
		   (equal (car a) (caar s) f)
		   (equal (cadr a) (cadar s) f)
		   (setq c (cons (car s) c))
		   (setq s (cdr s))
	      )
       )
       ;; Result
       (setq r (cons c r))
     )
;;;	 (setq n 0)
;;;	 ;; Quick check
;;;	 (foreach l r
;;;	   (setq n (1+ n))
;;;	   (foreach e l (entmod (append (entget (last e)) (list (cons 62 n)))))
;;;	 )
    )
  )
  (princ)
)
Quote

Command: FOO
Select objects: Specify opposite corner: 130680 found
Select objects:
< Elapsed time: 4.61 seconds. >

image.png.6fd3733e2ea701eda7941069df544818.png

Edited by ronjonp
  • Like 2
  • Thanks 1
Link to comment
Share on other sites

55 minutes ago, ronjonp said:

Do a presort like so to speed this up. This took ~5s to process 130,000 lines.

(defun c:foo (/ a b c e f n r s)
  ;; RJP » 2022-04-14
  ;; Groups a list of lists of lines that have similar angles and lengths
  (setq f 1e-1)
  (cond
    ((setq s (ssget '((0 . "LINE"))))
     (setq s (mapcar '(lambda (e)
			(setq a (vlax-curve-getstartpoint e))
			(setq b (vlax-curve-getendpoint e))
			(list (rem (angle a b) pi) (distance a b) e)
		      )
		     (vl-remove-if 'listp (mapcar 'cadr (ssnamex s)))
	     )
     )
     ;; Presort by sum of angle and length
     (setq s (vl-sort s (function (lambda (r j) (< (+ (cadr r) (car r)) (+ (cadr j) (car j)))))))
     ;; While we have a list
     (while (setq a (car s))
       ;; Get first item
       (setq s (cdr s))
       ;; Add first item to temp list 'c'
       (setq c (cons a c))
       ;; While we have a list 's' and the angle and length is 'equal', compile temp list 'c'
       (while (and s
		   (equal (car a) (caar s) f)
		   (equal (cadr a) (cadar s) f)
		   (setq c (cons (car s) c))
		   (setq s (cdr s))
	      )
       )
       ;; Result
       (setq r (cons c r))
     )
;;;	 (setq n 0)
;;;	 ;; Quick check
;;;	 (foreach l r
;;;	   (setq n (1+ n))
;;;	   (foreach e l (entmod (append (entget (last e)) (list (cons 62 n)))))
;;;	 )
    )
  )
  (princ)
)

image.png.6fd3733e2ea701eda7941069df544818.png

This is a very good idea, thanks a lot

Link to comment
Share on other sites

35 minutes ago, ekko said:

This is a very good idea, thanks a lot

Glad to help :) 

If you compile the code it should be even faster...

 

Yup .. over 2x

Quote

Command: FOO2
Select objects: Specify opposite corner: 130680 found
Select objects:
< Elapsed time: 2.094 seconds. >

 

Edited by ronjonp
  • Thanks 1
Link to comment
Share on other sites

7 minutes ago, ronjonp said:

@ekko Redownload the code .. I had forgotten to reset the temp list which gives very incorrect results. 🤪

The point is not the code, but your logic approach, you have solved my problem,  I have a doubt (setq f 1e-1) I can't understand this. thanks again for your help bro wish you a happy life😀

Edited by ekko
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...