Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Efficient code to see if set of points fall on a set of lines.

10 REPLIES 10
Reply
Message 1 of 11
Anonymous
160 Views, 10 Replies

Efficient code to see if set of points fall on a set of lines.

I currently have code to check a line against as list of points.
If any of the points fall on the line then the line gets deleted from an
anonymous block.

How can I efficiently code this for multiple lines against a set of
points?
10 REPLIES 10
Message 2 of 11
Anonymous
in reply to: Anonymous

(defun IsAnyPointOnLine (PointsList LineEName FuzzFactor
/ P1 P2 Elist ReturnValue
)
(setq P1 (cdr (assoc 10 (setq Elist (entget LineEName))))
P2 (cdr (assoc 11 EList))
)
(foreach Point PointsList
(if (equal (distance P1 P2)
(+ (distance Point P2) (distance Point P1))
FuzzFactor
)
(setq ReturnValue T PointsList NIL)
)
)
ReturnValue
)

jrf
Member of the Autodesk Discussion Forum Moderator Program
Please do not email questions unless you wish to hire my services

In article <3BB4998C.908C9FB@bbsae.com>, Mike Hutchinson wrote:
> I currently have code to check a line against as list of points.
> If any of the points fall on the line then the line gets deleted from an
> anonymous block.
>
> How can I efficiently code this for multiple lines against a set of
> points?
>
Message 3 of 11
PeterW
in reply to: Anonymous

PMJI, but would it not be more 'efficient' to use WHILE instead of FOREACH?
Message 4 of 11
mhutchinson
in reply to: Anonymous

(defun redefblk (blk1 pntlst / name head ent entlst)
(setq EntNameLst2Del (mapcar '(lambda (pnt)
(cdr (assoc '5 (entget (car (nentselp pnt)))))
)
pntlst
)
)
(setq name (cdr (assoc '2 (entget blk1)))
head (tblsearch "block" name)
ent (cdr (assoc -2 head))
)
(entmake (reverse (cdr (reverse head))))
(while ent
(setq entlst (entget ent))
(setq handle (cdr (assoc '5 entlst)))
(setq Keeper (not (member handle EntNameLst2Del)))
(if Keeper (entmake entlst))
(setq ent (entnext ent))
)
(entmake (list (cons '0 "ENDBLK")))
(entupd blk1)
)

This works but not when the entities are close together or I am zoomed out very far.
What do you think?
Message 5 of 11
Anonymous
in reply to: Anonymous

In article , PeterW wrote:
> PMJI, but would it not be more 'efficient' to use WHILE instead of FOREACH?

I assume you mean because you can terminate the while loop as soon as you
find a point on the line? I checked it out some, and the results are
interesting.

I thought that setting PointsList to nil if I found a matching point would
terminate the foreach. It doesn't. Foreach makes its own local variable
stack for its first argument, and apparently it works off a copy of its
second argument in that stack, which you can't get at to set it to nil.

So it would appear that the speed of foreach versus while would depend on the
length of the point list, whether or not there are any points in the list
that are on the line, and the position of the first point in the list that's
on the line. And it does. Using the following for the "while" version:

(defun IsAnyPointOnLine2 (PointsList LineEName FuzzFactor
/ P1 P2 Elist ReturnValue Counter
)
(setq P1 (cdr (assoc 10 (setq Elist (entget LineEName))))
P2 (cdr (assoc 11 EList))
Counter (length PointsList)
)
(while (and (not ReturnValue) (<= 0 (setq Counter (1- Counter))))
(if (equal (distance P1 P2)
(+ (distance (nth Counter PointsList) P2)
(distance (nth Counter PointsList) P1)
))
FuzzFactor
)
(setq ReturnValue T)
)
)
ReturnValue
)

(note that I'm processing the point list backwards in this version, relative
to the first version).

With a list of 100 points, the while version takes almost 100% longer if none
of the points are on the line and just over 90% less time if the first point
tested is in the list. With ten points in the list, while is about 15%
slower if none of the points are on the line and 60% faster if the first
point tested is on the line. With two points in the list, the two versions
are equal whether or not one of the points is on the line. With ten points
in the list and only the fifth point tested on the line, the while version is
about 17% faster.

So the answer to your question is "maybe, depending on the statistics of the
input data". If you usually expect no points to be on the line, foreach is
faster. If you usually expect at least one of the points to be on the line
and the first point that the routine finds on the line is equally likely to
be at any position in the list, while is probably a tad faster. If you
usually expect at least one of the points to be on the line and it is likely
that one of the points in the first half of the list that the routine
processes, while is better.

jrf
Member of the Autodesk Discussion Forum Moderator Program
Please do not email questions unless you wish to hire my services
Message 6 of 11
Anonymous
in reply to: Anonymous

You don't need th single quotes in front of literal numbers; '5 can be
written as 5.

Your selection problem is a tough one ... there are limitations in
on-screen selection that you're running in to. What is the purpose of
this routine?

jrf
Member of the Autodesk Discussion Forum Moderator Program
Please do not email questions unless you wish to hire my services

In article , Mhutchinson wrote:
> (defun redefblk (blk1 pntlst / name head ent entlst)
> (setq
> EntNameLst2Del (mapcar '(lambda (pnt)
> (cdr (assoc '5 (entget (car
> (nentselp pnt)))))
> )
> pntlst
> )
> )
>
> (setq name (cdr (assoc '2 (entget blk1)))
> head
> (tblsearch "block" name)
> ent (cdr (assoc -2 head))
> )
>
> (entmake (reverse (cdr (reverse head))))
> (while ent
>
> (setq entlst (entget ent))
> (setq handle (cdr (assoc '5
> entlst)))
> (setq Keeper (not (member handle EntNameLst2Del)))
>
> (if Keeper (entmake entlst))
> (setq ent (entnext ent))
>
> )
> (entmake (list (cons '0 "ENDBLK")))
> (entupd blk1)
> )
>
> This works but not when the entities are close together or I am
> zoomed out very far.
> What do you think?
>
Message 7 of 11
Anonymous
in reply to: Anonymous

Hi Jon,
Looks good, but what about the coordinate system of the nested entity and the
block? Is some sort of call to TRANS appropriate? Perhaps the calling function
should be responsible for feeding the endpoints and the pick points to this function
rather than an ename.

Doug
Message 8 of 11
Anonymous
in reply to: Anonymous

The purpose is to redefine the block to exclude unwanted geometry.
You can pass in the point list and the block ename... if the point lies on
an entity within the block then that entity is written out of the block.
I only include the ' on the 5 simply because this is the way that I was
taught... and the online help adds this
when using assoc with entity association lists.
In my application I am running a solprof command on a solid... I have
previously stored some calculated points
in 1011 group and attached it as xdata to a block. Then when the 2d
geometry gets recreated on subsequent solprof
commands the unwanted geometry marked by a list of points ...(1011 x y
z)(1011 x y z)... is excluded from the anonymous block.

Previously I was using an algorythm to check the point against all the
geometry to see if it lies on some portion of that geometry...
I thought that nentselp would work much more efficiently than the 100
lines (or so) of code I was using. It does work much better
when the geometry is not close together, but fails to eliminate the
appropriate geometry when zoomed out such that the pickbox aperture size
includes other close geometry..
I thought that I could reset the aperture size to fix this but this
doesn't seem to make much difference to the successfull run of my code.
I also tried performing a "nea" snap mode modifier to the point... this
doen't help much either.

Jon Fleming wrote:

> You don't need th single quotes in front of literal numbers; '5 can be
> written as 5.
>
> Your selection problem is a tough one ... there are limitations in
> on-screen selection that you're running in to. What is the purpose of
> this routine?
>
> jrf
> Member of the Autodesk Discussion Forum Moderator Program
> Please do not email questions unless you wish to hire my services
>
> In article , Mhutchinson wrote:
> > (defun redefblk (blk1 pntlst / name head ent entlst)
> > (setq
> > EntNameLst2Del (mapcar '(lambda (pnt)
> > (cdr (assoc '5 (entget (car
> > (nentselp pnt)))))
> > )
> > pntlst
> > )
> > )
> >
> > (setq name (cdr (assoc '2 (entget blk1)))
> > head
> > (tblsearch "block" name)
> > ent (cdr (assoc -2 head))
> > )
> >
> > (entmake (reverse (cdr (reverse head))))
> > (while ent
> >
> > (setq entlst (entget ent))
> > (setq handle (cdr (assoc '5
> > entlst)))
> > (setq Keeper (not (member handle EntNameLst2Del)))
> >
> > (if Keeper (entmake entlst))
> > (setq ent (entnext ent))
> >
> > )
> > (entmake (list (cons '0 "ENDBLK")))
> > (entupd blk1)
> > )
> >
> > This works but not when the entities are close together or I am
> > zoomed out very far.
> > What do you think?
> >
Message 9 of 11
PeterW
in reply to: Anonymous

Your results may be interesting, but not as
interesting as your 'while' version.

I don't follow the logic of repeatedly
evaluating '(distance P1 P2)' in each loop
iteration, if P1 and P2 are constants (?)

Also, why use NTH twice in each loop
interation to get the same item out of
the list? Unless I'm wrong, NTH must
walk the list to get to the "nth" item
in it, no?

In light of how you coded your WHILE
version, I'm not suprised it is slow,
as it seems to be doing more work than
it needs to do.

By using "while instead of foreach",
what I really meant was to use WHILE,
SETQ, and CDR to walk the list, and
testing the first item (via CAR) on
each loop:

(defun isAnyPointOnLine? (pointslist line fuzz /
entdata p1 p2 len)

(setq entdata (entget line))
(setq p1 (cdr (assoc 10 entdata))
p2 (cdr (assoc 11 entdata))
)

; this is a constant:

(setq len (distance p1 p2))

; add dummy value to front of list

(setq pointslist (cons nil pointlist))

; loop while there are more points
; and no point is found on the line

(while
(and (setq pointslist (cdr pointslist))
(not (equal len
(+
(distance p1 (car pointslist))
(distance p2 (car pointslist))
)
fuzz
)
)
)
)

; if list is empty nothing was found

(or pointslist)
)
Message 10 of 11
Anonymous
in reply to: Anonymous

That sounds reasonable.

jrf
Member of the Autodesk Discussion Forum Moderator Program
Please do not email questions unless you wish to hire my services

In article , Doug Broad wrote:
> Hi Jon,
> Looks good, but what about the coordinate system of the nested entity and the
> block? Is some sort of call to TRANS appropriate? Perhaps the calling function
> should be responsible for feeding the endpoints and the pick points to this function
> rather than an ename.
>
> Doug
>
Message 11 of 11
Anonymous
in reply to: Anonymous

Hum. The part about (distance p1 p2) is certainly true, and I just
missed that. However, your version is LOTS faster than mine, around
95% faster. I'm going to have to think about that ...

jrf
Member of the Autodesk Discussion Forum Moderator Program
Please do not email questions unless you wish to hire my services

In article , PeterW wrote:
> Your results may be interesting, but not as
> interesting as your 'while' version.
> I don't follow the logic of repeatedly
> evaluating '(distance P1 P2)' in each loop
> iteration, if P1 and P2 are constants (?)
> Also, why use NTH twice in each loop
> interation to get the same item out of
> the list? Unless I'm wrong, NTH must
> walk the list to get to the "nth" item
> in it, no?
> In light of how you coded your WHILE
> version, I'm not suprised it is slow,
> as it seems to be doing more work than
> it needs to do.
> By using "while instead of foreach",
> what I really meant was to use WHILE,
> SETQ, and CDR to walk the list, and
> testing the first item (via CAR) on
> each loop:
> (defun isAnyPointOnLine? (pointslist line fuzz /
> entdata p1 p2 len)
> (setq entdata (entget line))
> (setq p1 (cdr (assoc 10 entdata))
> p2 (cdr (assoc 11 entdata))
> )
> ; this is a constant:
> (setq len (distance p1 p2))
> ; add dummy value to front of list
> (setq pointslist (cons nil pointlist))
> ; loop while there are more points
> ; and no point is found on the line
> (while
> (and (setq pointslist (cdr pointslist))
> (not (equal len
> (+
> (distance p1 (car pointslist))
> (distance p2 (car pointslist))
> )
> fuzz
> )
> )
> )
> )
> ; if list is empty nothing was found
> (or pointslist)
> )
>

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

Post to forums  

Autodesk Design & Make Report

”Boost