Author Topic: nesting foreach commands  (Read 3209 times)

0 Members and 1 Guest are viewing this topic.

curmudgeon

  • Newt
  • Posts: 194
nesting foreach commands
« on: March 23, 2009, 02:35:18 AM »
I am having no luck either getting this to run or debugging. I want to do something like this:

(foreach n pnt_lst
   (do something with n)   
      (foreach k list_made_in_previous
         (do something with n & k )
      );;; end k
);;; end n

am I trying something that cannot work, or is it more likely that I just typed the syntax wrong?

Never express yourself more clearly than you are able to think.

pkohut

  • Guest
Re: nesting foreach commands
« Reply #1 on: March 23, 2009, 02:55:25 AM »
Don't quote me on this, lisp isn't my cup of tea, but first thought is your
statement is being interpreted as:
(foreach n pnt_lst
   (do something with n)   
(foreach k list_made_in_previous
   (do something with n & k )
   );;; end k
);;; end n

and you might need to change it to something like this (not tried or tested)

Code: [Select]
(foreach n pnt_lst
  (progn
   (do something with n)   
      (foreach k list_made_in_previous
         (do something with n & k )
      );;; end k
) ;_ progn
);;; end n


Sorry, that's the best I can come up with at this time.

Paul

gile

  • Gator
  • Posts: 2507
  • Marseille, France
Re: nesting foreach commands
« Reply #2 on: March 23, 2009, 03:40:57 AM »
Hi,

It's quite difficult to understand what you want to do.

Assuming pnt_lst is a points list => n is a point (list of doubles)
(do something with n) returns a list [list_made_in_previous] => k is an item of this list

Code: [Select]
(foreach n pnt_lst
  (foreach k (do something with n))
  (do something with n & k)
)

If list_made_in_previous is a list which countains each (do something with n) results (ex: a list of tranformed points)

Code: [Select]
(foreach n pnt_lst
  (setq k (do something with n))
  (do something with n & k)
)
Speaking English as a French Frog

curmudgeon

  • Newt
  • Posts: 194
Re: nesting foreach commands
« Reply #3 on: March 23, 2009, 08:34:01 AM »
read if you have interest - I think I am trying a different, but very similar, approach.

the real world problem is a single line architectural plan.
the geometry is all polygons, in autolisp LWPOLYLINES, fitting together like pieces in a puzzle.
my goal is to be able to create point lists for the apparent intersections and to insert these as new vertexes.

I start with the perimeter and create a point list.
a point list for a simple rectangle might look like this:
((0.0 0.0) (50.0 0.0) (50.0 30.0) (0.0 30.0))

I modify that list so that instead of representing the vertexes of a rectangle,
the new list represents the endpoints of the implied segments.
(((0.0 0.0) (50.0 0.0)) ((50.0 0.0) (50.0 30.0)) ((50.0 30.0) (0.0 30.0)) ((0.0 30.0) (0.0 0.0)))

I create a filtered fence selection, the fence point list being a straight line: in this case the first would look like this:
f_pt_lst  ((6.12303e-018 0.1) (50.0 0.1))

I do get rounding error at times, I think it is because I am using polar to find these points.
with this point list for a fence selection, I (ssget "_F" f_pt_lst '((0 . "LWPOLYLINE") (8 . "rooms")))
and I have all the polygons that have vertexes "on" the first segment of the perimeter.

at this point, any method that would retrieve points on this perimeter segment would serve.

I am comfortable with stripping the points list from a LWPOLYLINE, so I try that first.
in my test file, the first entity in the selection set produces this list
((50.0 4.06105) (50.0 13.2111) (37.362 13.2111) (37.362 4.06105))

the second, and last in this example, polyline having endpoints on the perimeter is
((50.0 13.2111) (50.0 30.0) (25.0 30.0) (25.0 13.2111))

I create a repeat loop with (sslength selection_set) within which I
   get the point list for each adjacent polygon and
      extract only the points "on" the perimeter.

within the inner loop I thought I would insert the new points for each individual polygon,
but I was using car and cadr on BOTH lists
(car n) being the outer loop and should evaluate ((0.0 0.0) (50.0 0.0)) for the segment to add vertexes to.
then I was testing the angle implied from (caar points), which is (car n) in the foreach, to each point
in the second list, against (angle (0.0 0.0) (50.0 0.0) )

if you START at a point on the perimeter and follow the same angle, the point is on the line.
otherwise, not.

I don't have the points of the interior polygons until I am in the inner foreach.
but the points on the segment are "n" in the outer foreach.
so, I wanted to nest them and see if I could pass "n" into the inner "k" loop.
Never express yourself more clearly than you are able to think.

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: nesting foreach commands
« Reply #4 on: March 23, 2009, 08:59:56 AM »
Because points are not exact, that is there are rounding errors involved I use
Code: [Select]
(< (distance point1 point2) 0.00001)
to compare the points.

I did not quite follow what you are trying to accomplish, so if you post a DWG with a simple
example it would help explain your goal.
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

curmudgeon

  • Newt
  • Posts: 194
Re: nesting foreach commands
« Reply #5 on: March 23, 2009, 10:14:41 AM »
I have a polyline I have reduced to segments, if you will.
for a given set of points in a different list, I want to select the ones "on" that segment.
to do this, I was comparing the angle of the segment with the angle from one endpoint
of the segment to each point in the second list. I was using equal with a fuzz factor.

(equal angle_of_segment (angle segment_end_pt pt_from_lst) 0.001)

it gives good results, I can put that in my if statement and harvest the points I wanted.
now I want to sort that list, I think.

I am absolutely new to sorting lists. maybe I created a list that will be very hard to sort,
but it was in the form of ( ((distance from start point) (actual point)) ((distance from start point) (actual point)).....)
or
((0.0) ((50.0 0.0)) (30.0) ((50.0 30.0)) (13.2111) ((50.0 13.2111))......)
( (D)((PT)) (D)((PT)) (D)((PT)) ....)

it would be easy to have created
(0.0 (50.0 0.0) 30.0 (50.0 30.0) 13.211 (50.0 13.2111) ......)
(D (PT) D (PT).......)

or even (D x y D x y .......)

but I want to sort a list by distance from the start point so the vertexes come in sequence when I insert them.
if I am making any sense at all...

I have an example I was working from that sorted a text list:
(vl-sort my_lst (function (lambda (a b) (< (car a) (car b))))  )
that works on a list of the form:
(("164" "3B214") ("121" "3B095") ("115" "3B086") ("145" "3B02A")...)
gives
(("101" "3955F") ("102" "39894") ("103" "397E2") ("104" "3A2BB")...)

I GUESS I COULD
(list (rtos D) (rtos x) (rtos y)) to create my list and get
(("D" "x" "y") ("D" "x" "y") ("D" "x" "y")....)

but I really don't comprehend either function or lambda yet.
I would guess it might be
(vl-sort my_lst (function (lambda (a b c) (< (car a) (car b) (car c))))  )
for three items instead of two, but as I said, that would just be guessing, not understanding.


roy



Never express yourself more clearly than you are able to think.

curmudgeon

  • Newt
  • Posts: 194
Re: nesting foreach commands
« Reply #6 on: March 23, 2009, 10:46:47 AM »
I have something that works......

my list can be of the form (( real (real real)) ( real (real real)) ( real (real real))....)

and (vl-sort my_lst (function (lambda (a b) (< (car a) (car b))))) works

((30 (14 24)) (10 (111 3.5)) (112 (3 0.125)) (55 (121 3.15)))
yields
((10 (111 3.5)) (30 (14 24)) (55 (121 3.15)) (112 (3 0.125)))

but I would STILL like to know how and why.

thanks,

roy
Never express yourself more clearly than you are able to think.

SomeCallMeDave

  • Guest
Re: nesting foreach commands
« Reply #7 on: March 23, 2009, 11:09:15 AM »
Roy,

This may not apply to your problem, but in the past with somewhat similar problems, I have used 2 lists,  one being the list of distances and the other being XY list.

I sort the distance list using  vl-sort-i.  This function returns the indices of the list sorted by whatever function you choose.  Then you can use nth and the value of the sorted distance list to reach into the XY list to get the coordinates in 'distance order'.

Here is a snippet that takes the 'crossing points' of a fenced selection,  sorts the crossing point list by distance, then reaches into the selection set to the entities
Code: [Select]
;; build a distance list based on my CrossPtList which, in this case, comes from SSNAMEX
  (repeat (length CrossPtList)
       (if DistList
           (setq DistList (append DistList (list (vlax-curve-GetDistAtPoint Ent1 (vlax-curve-getClosestPointTo Ent1 (nth count CrossPtList))))))
           (setq DistList (list (vlax-curve-GetDistAtPoint Ent1 (vlax-curve-getClosestPointTo Ent1 (nth count CrossPtList)))))
       );if
       (setq count (+ 1 count))         
    );repeat

  ;sort the distance list, but return the sorted indices
    (setq DistListSortI (vl-sort-i DistList '<)
          count 0
    );setq
   
;;
    (repeat (length DistListSortI)
       (setq currEnt (ssname ss1 (nth count DistListSortI)) ;; grab the entity in 'distance order'
               ;;; blah blah  - do something with the Entity here
        );setq
       
    );;repeat

I'm not even sure this is applicable to your problem, but maybe it will help.

curmudgeon

  • Newt
  • Posts: 194
Re: nesting foreach commands
« Reply #8 on: March 23, 2009, 11:45:45 AM »
thanks. I studied your example and I believe I see what you have done. you create two lists, sort the indices, and use that to "reach into" your other list. check out the (vl-sort my_lst (function (lambda (a b) (< (car a) (car b))))). it does sort the combined list.

your method keeps the lists separate and fabricates the sort link. mine combines, sorts, and then needs to separate out the lists again.
I have no idea which one is best. :)

another hurdle, the next one I guess, is that my sorted list has duplicates in it. in the example in the autolisp help file, duplicates were removed in the process. looking more closely, the help file states, "Duplicate elements may be eliminated from the list. "

May is a wonderful month. looks good on my calendar. I don't like to see it so much in an explanation of what a function should do.

better to not create them in the first place, but I guess I see how to remove duplicates. I am almost home.


thanks,

roy
Never express yourself more clearly than you are able to think.

adalea03

  • Guest
Re: nesting foreach commands
« Reply #9 on: March 29, 2009, 10:58:54 AM »
I use a variation of this often when organizing lists.

Code: [Select]
  (setq lst-03 nil)
  (foreach xi lst-01
    ; do something (or just continue)
    (foreach ix lst-02
      (if (= xi (cadr ix))
        (setq lst-03 (append lst-03 (list ix))))
      ); end foreach ix lst-02
    ); end foreach ix lst-01

Tony

alanjt

  • Needs a day job
  • Posts: 5352
  • Standby for witty remark...
Re: nesting foreach commands
« Reply #10 on: March 30, 2009, 09:26:53 AM »
Because points are not exact, that is there are rounding errors involved I use
Code: [Select]
(< (distance point1 point2) 0.00001)
to compare the points.

I did not quite follow what you are trying to accomplish, so if you post a DWG with a simple
example it would help explain your goal.

alan, is there any difference in using equal, to what you are doing?
Code: [Select]
(equal point1 point2 0.00001)
i'm not trying to tell you how to do things, i'm really just curious. you know a lot more about lisp than i do.
Civil 3D 2019 ~ Windohz 7 64bit
Dropbox

CAB

  • Global Moderator
  • Seagull
  • Posts: 10401
Re: nesting foreach commands
« Reply #11 on: March 30, 2009, 10:05:28 AM »
Just proposing a different method. EQUAL with fuzz will work as well.
Another tool in the tool box. 8-)
I've reached the age where the happy hour is a nap. (°¿°)
Windows 10 core i7 4790k 4Ghz 32GB GTX 970
Please support this web site.

alanjt

  • Needs a day job
  • Posts: 5352
  • Standby for witty remark...
Re: nesting foreach commands
« Reply #12 on: March 30, 2009, 10:34:44 AM »
Just proposing a different method. EQUAL with fuzz will work as well.
Another tool in the tool box. 8-)
cool :)
Civil 3D 2019 ~ Windohz 7 64bit
Dropbox