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

Find included angles of Pline

30 REPLIES 30
SOLVED
Reply
Message 1 of 31
Anonymous
7152 Views, 30 Replies

Find included angles of Pline

My code below creates a list of included angles of a closed polyline. Unfortunately it's not quite working properly.

I am finding that not all angles in the list are correct for example if I select a 4 sided right angle rectangle the list will

return  

 (270.0 90.0 90.0 90.0)

for the four vertices. What is happening is that the first item in the list is a bearing rather than an included angle.

This seems to happen with any polygon shape.

Is there someone who can tweak my code so that it returns a list of all included angles for any polygon shape?

any help would be sincerly appreciated!

 

(defun c:PlineAngl (/ PntLst l enaPline eprPline DegList AngleList )
(setq enaPline(car (entsel "\nSelect closed pline : ")))
(setq eprPline(entget enaPline))
(foreach lstTemp eprPline
(if (= (car lstTemp) 10)
(setq PntLst (append PntLst (list (cdr lstTemp))))
);if
);foreach
(setq PntLst (reverse PntLst));Points list
(if
(< 2 (length PntLst))
;pi angle radians list
(setq AngleList (mapcar (function (lambda (a b c) (abs (- (angle a b) (angle b c)))))
      PntLst
(setq l (cons (last PntLst) PntLst))
        (cons (cadr (reverse PntLst)) l)
);mapcar
);setq 
);if
(setq DegList (mapcar '(lambda (a) (* a (/ 180 pi))) AngleList));convert list to degrees
(princ DegList)
(princ)
);defun

 

30 REPLIES 30
Message 2 of 31
Anonymous
in reply to: Anonymous

If I understand correctly, this should work for you.  What I saw the issue as, was if one of the angles is 0.0, and the other is greater than 180 ( pi ), then you need to get the angle between the greatest it could be 360 and said number.

 

(setq cnt 0)
(setq MaxCnt (1- (length PntLst)))
(while (<= cnt MaxCnt)
    (setq AngleList
        (cons
            (
                (lambda ( a b )
                    (abs
                        (-
                            (if
                                (and
                                    (zerop a)
                                    (> b pi)
                                )
                                (* pi 2.)
                                a
                            )
                            (if
                                (and
                                    (zerop b)
                                    (> a pi)
                                )
                                (* pi 2.)
                                b
                            )
                        )
                    )
                )
                (angle
                    (nth cnt PntLst)
                    (nth (if (zerop cnt) MaxCnt (1- cnt)) PntLst)
                )
                (angle
                    (nth cnt PntLst)
                    (nth (if (equal cnt MaxCnt) 0 (1+ cnt)) PntLst)
                )
            )
            AngleList
        )
    )
    (setq cnt (1+ cnt))
)

Message 3 of 31
Anonymous
in reply to: Anonymous

After I wrote the message explaining the code, it came to me that it could be written like this also:

 

(setq cnt 0)
(setq MaxCnt (1- (length PntLst)))
(while (<= cnt MaxCnt)
    (setq AngleList
        (cons
            (abs
                (-
                    (rem
                        (angle
                            (nth cnt PntLst)
                            (nth (if (zerop cnt) MaxCnt (1- cnt)) PntLst)
                        )
                        pi
                    )
                    (rem
                        (angle
                            (nth cnt PntLst)
                            (nth (if (equal cnt MaxCnt) 0 (1+ cnt)) PntLst)
                        )
                        pi
                    )
                )
            )
            AngleList
        )
    )
    (setq cnt (1+ cnt))
)

Message 4 of 31
Kent1Cooper
in reply to: Anonymous

Some questions for the OP in relation to this routine:

 

If you used this on an American-flag-style five-pointed star shape, would you want it to report the 252-degree angles for the concave corners, that is, the included angle as viewed from inside the shape?  Without testing it, I suspect the routine will return incorrect angles for concave bends, such as that, the inside corner of Pacman's mouth, etc., since it looks like it can only feed back angles less than 180 degrees.  There may also be a related problem for bends where the 0-degree direction lies between the directions of adjacent segments, but I'd have to think about that some more.

 

Might the Polylines you run it on ever include arc segments?

 

And there would be a problem if a Polyline is closed only visually/geometrically, but not closed by AutoCAD's definition, because its last vertex will be at the same location as its first one.  As I recall, (angle) always returns 0 if given the same point twice, so your first returned angle could be wrong.  If that's a possibility, you could put in a (vlax-curve-isClosed) check, and adjust the first points compared if it's not.

 

It looks like it would return the list of angles in radians, so if your original description is any indication, you would want to include a conversion to degrees.

Kent Cooper, AIA
Message 5 of 31
Anonymous
in reply to: Anonymous

Many Thanks!!! T. Willey - yes your code worked. That has solved the problem of the first angle  Smiley Happy

Message 6 of 31
Anonymous
in reply to: Anonymous

You're welcome.

 

Kent brought up a good issue about the angle.  I was thinking about that, but couldn't find an easy anwer quickly.  But if that doesn't matter, then it's all good.

Message 7 of 31
Anonymous
in reply to: Kent1Cooper

Kent -

thank you

In regards to a polyline with arc segments in my case I would have none, and it would be easy to error check for a closed pline that has been closed with "close" rather than picking the endpoint the same as the start point.

 

Yes your point regarding included angles greater than 90 degrees - Angle out put is not the "internal" angle. The angles

greater than 180 degrees are the ones I am interested in - I want to filter these out from my points list. I am not sure how this can be done - maybe a genius can figure this out?

 

Message 8 of 31
Anonymous
in reply to: Anonymous

Message 9 of 31
Anonymous
in reply to: Anonymous

I took the liberty to modify the routine to display only the list of angles, but the latter appears wrong angle.

 

The modified (without any formatting)

 

 

(defun c:AngPline (/ nolist PntLst OldOsm lstTemp pt1
pt2 pt3 Points ang1 inspt
enaPline eprPline ang2 OldDIMSE1 OldDIMSE2
)
;------------------------------------------------
;; This function returns the deflection angle (in radians) of two angles:
(defun @delta (a1 a2)
(cond
((> a1 (+ a2 pi))
(setq a2 (+ a2 (* 2 pi)))
)
((> a2 (+ a1 pi))
(setq a1 (+ a1 (* 2 pi)))
)
)
(- a2 a1)
);defun
;------------------------------------------------
(setq angles '())
(setq OldOsm (getvar "OSMODE")
OldDIMSE1 (getvar "DIMSE1")
OldDIMSE2 (getvar "DIMSE2")
)
(setvar "OSMODE" 32)
(setvar "DIMSE1" 1)
(setvar "DIMSE2" 1)

(cond
((not
(setq enaPline (car (entsel "\nSelect closed pline: ")))
)
)
((/= (cdr (assoc 0 (setq eprPline (entget enaPline))))
"LWPOLYLINE"
)
(alert "Selected object is not a lwpolyline.")
)
(T
(foreach lstTemp eprPline
(if (= (car lstTemp) 10)
(setq PntLst (append PntLst (list (cdr lstTemp))))
);if
);foreach
;(if (minusp sum)(setq PntLst (reverse PntList)))
(setq PntLst (reverse PntLst))
(setq Points PntLst)

;Get angle for first vertice
(setq firstpt (car Points)
secondpt (cadr Points)
lastpt (last Points))
(setq ang (abs(@delta (angle firstpt secondpt) (angle secondpt lastpt))))
(setq angles (cons (angtos ang) angles))
(setq inspt1 (polar firstpt (+ (angle firstpt secondpt) ang)
1000));temp value of 1000
;(command "_dim1" "ang" "" firstpt secondpt lastpt inspt1 "" "")


;Get angle for last vertice
(setq RevPoints ( reverse Points ))
(setq lastpt (car RevPoints)
secondlastpt (cadr RevPoints)
firstpt (last RevPoints))
(setq ang2 (abs (@delta (angle lastpt firstpt) (angle lastpt secondlastpt))))
(setq angles (cons (angtos ang2) angles))
(setq inspt2 (polar lastpt (+ (angle lastpt firstpt) ang2) 1000));temp
value of 1000
;(command "_dim1" "ang" "" lastpt firstpt secondlastpt inspt2 "" "")

;get angles for remaining vertices
(while
(and
(setq pt1 (car Points)
pt2 (cadr Points)
pt3 (caddr Points))
);and
(setq ang1 (abs (@delta (angle pt2 pt3) (angle pt2 pt1))))
(if (> ang1 (* 1.0 pi))
(setq ang1 (- (* 2.0 pi) ang1))
(setq angles (cons (angtos ang1) angles))
)

(setq inspt (polar pt2 (+ (angle pt2 pt3) ang1) 1000));temp value of 1000
;(command "_dim1" "ang" "" Pt2 Pt3 Pt1 inspt "" "")
;(command "line" inspt Pt2 "");temp line to check where inspt is
(setq Points (cdr Points))
);while
);T
);cond
(setvar "OSMODE" OldOsm)
(setvar "DIMSE1" OldDIMSE1)
(setvar "DIMSE1" OldDIMSE2)
(princ angles)
(princ)
)

 

 

Message 10 of 31
Kent1Cooper
in reply to: Anonymous


@Anonymous wrote:

....

Yes your point regarding included angles greater than 90 degrees - Angle out put is not the "internal" angle. The angles greater than 180 degrees are the ones I am interested in - I want to filter these out from my points list. .... 


I'm confused.  My issue was with angles greater than 180, not greater than 90.  When you say "internal" angle, are you referring to the angle from the point of view of inside the shape [that's how I think of it], whether it's acute, right, obtuse, straight or reflex?  Or do you mean the lesser of the two possible angle measurements between a pair of adjacent segments, whether that's inside or outside the shape?  There's always one less than 180 degrees, and one greater [or two at 180 if it's a straight angle].

 

Then there's the possibility that you want the size of the change in direction, the angle that it bends, the angle between the extension of a segment and the next segment.  For example, in a regular hexagon, each internal angle [by my definition] is 120 degrees, but the amount of each change in direction, or each bend angle, is 60 degrees.  What would you want the list of angles to be for that?  [In your original example of a rectangle, 90 degrees is both the internal angle and the bend angle, so that doesn't resolve it.]

 

Some more examples might be helpful.  For a Polyline that goes from 0,0 to 2,0 to 1,1 to 2,2 to 0,2 and closes, what should the list of angles look like?  If you want what I think of as the internal angles, it would be [starting with the angle at the 0,0 corner] (90 45 270 45 90).  If you just want the lesser of the possible angles, whether inside or outside, it would be (90 45 90 45 90).  If you want change-in-direction bend angles, it would be (90 135 90 135 90).  And maybe you'd like some of those negative, such as the middle one in that last list, because from the point of view of proceeding along the Polyline, it bends 90 degrees in the opposite direction from the other 90-degree bends.

Kent Cooper, AIA
Message 11 of 31
Anonymous
in reply to: Kent1Cooper

Kent - sorry - mea culpa - (I wanted to edit after I sent the post but this forum won't let you edit) I meant to explain that I wanted to find angles (as you say from the inside of the shape) that are 180 degrees or more. Obviously this will never happen with a four sided shape. However shapes with 5 or more sides this can occur. In your example of the american star there are some angles(inside the star) that 180 degrees or more (not the pointy bits) 

 

And In your example .....

from 0,0 to 2,0 to 1,1 to 2,2 to 0,2 and closes, what should the list of angles look like?  If you want what I think of as the internal angles, it would be [starting with the angle at the 0,0 corner] (90 45 270 45 90)

 

Its this angle of 270 degrees I want to isolate from the points list.

 

To let you know my ultimate goal - In my overall code I am inserting blocks at each pline vertex, However internal angles  that are 180 degrees or greater I do not want a block inserted. Perhaps this can not be done?

 

many thanks Kent for your input........

 

 

Also thanks Rogiero for your code another interesting way of writing it. However I still have the problem of finding certain angles (see above) from the points list

Message 12 of 31
Kent1Cooper
in reply to: Anonymous


@Anonymous wrote:

....I wanted to find angles (as you say from the inside of the shape) that are 180 degrees or more. Obviously this will never happen with a four sided shape. ....


It can, actually, e.g.:  0,0 to 2,1 to 4,0 to 2,4 and close.

 

I'll think about the rest of it, and look more closely than I have so far into what others have suggested.

 

It will probably require inclusion of something to determine in which direction the Polyline was drawn [CW vs. CCW], which has been a topic of some earlier threads here.  In one drawn using the point series above, the bend at 2,1 will be turning to the right from the point of view of traveling along the Polyline.  You'll want the reflex angle on your left, but in order to know that's the one you want, you'll need to know that the overall shape is drawn counter-clockwise, which will tell you that all bends to the right involve reflex internal angles.  If the 2,4 were 2,-1 instead, with all other points unchanged, it would be drawn clockwise, which means that bends to the right are acute/obtuse internal angles, and you would want the obtuse angle instead of the reflex one.  With only the locations of the first three points to go by, it's not possible to determine that, so there will be more involved than just a point list.

Kent Cooper, AIA
Message 13 of 31
Anonymous
in reply to: Anonymous

I think this will do what you want.  Make sure you have a function called ' RTD ' ( and it is loaded ) to transform the radians to degress, or just change the call from ' RTD ' to something else, or the program will error.

 

(defun c:Test ( / ActDoc CurSp Sel Data PlObj PtList cnt MaxCnt Ang tempAng Pt tempObj AngList Norm Pt2 tempAng2 )

    (vl-load-com)
    (setq ActDoc (vla-get-ActiveDocument (vlax-get-Acad-Object)))
    (setq CurSp
        (vlax-get
            ActDoc
            (if (equal (getvar 'CvPort) 1)
                'PaperSpace
                'ModelSpace
            )
        )
    )
    (if
        (and
            (setq Sel (entsel "\n Select closed polyline: "))
            (setq Data (entget (car Sel)))
            (= (cdr (assoc 0 Data)) "LWPOLYLINE")
            (equal (logand 1 (cdr (assoc 70 Data))) 1)
            (setq PlObj (vlax-ename->vla-object (car Sel)))
        )
        (progn
            (foreach i Data
                (if (equal (car i) 10)
                    (setq PtList (cons (cdr i) PtList))
                )
            )
            (setq PtList (reverse PtList))
            (setq cnt 0)
            (setq MaxCnt (1- (length PtList)))
            (while (<= cnt MaxCnt)
                (setq Ang
                    (abs
                        (-
                            (setq tempAng
                                ;(rem
                                    (angle
                                        (setq Pt (nth cnt PtList))
                                        (setq Pt2 (nth (if (zerop cnt) MaxCnt (1- cnt)) PtList))
                                    )
                                    ;pi
                                😉
                            )
                            (setq tempAng2
                                (if
                                    (equal
                                        (setq tempAng2
                                            ;(rem
                                                (angle
                                                    Pt
                                                    (nth (if (equal cnt MaxCnt) 0 (1+ cnt)) PtList)
                                                )
                                                ;pi
                                            😉
                                        )
                                        0.
                                    )
                                    (* pi 2.)
                                    tempAng2
                                )
                            )
                        )
                    )
                )
                (setq Pt (trans Pt (setq Norm (cdr (assoc 210 Data))) 0))
                (setq StPt (polar Pt tempAng 0.0001))
                (setq tempObj (vlax-invoke CurSp 'AddRay StPt (trans Pt2 Norm 0)))
                (vlax-invoke tempObj 'Rotate Pt (* (/ Ang 2.) (if (< tempAng tempAng2) 1. -1.)))
                (if
                    (equal
                        (rem
                            (/ (length (vlax-invoke PlObj 'IntersectWith tempObj acExtendNone)) 3)
                            2
                        )
                        1
                    )
                    (setq AngList (cons Ang AngList))
                    (setq AngList (cons (- (* pi 2.) Ang) AngList))
                )
                ;(print (car AngList))
                ;(getstring "\n Hit enter to continue: ")
                (if tempObj (vla-Delete tempObj))
                (setq tempObj nil)
                (setq cnt (1+ cnt))
            )
        )
    )
    (print (mapcar (function RTD) (reverse AngList)))
    (princ)
)

Message 14 of 31
Anonymous
in reply to: Anonymous

Hi  125minden,

 

Thanks, but the routine is not my own.

 

Please check the last link to see the credits of the routine. All the credits to the authors.

 

Best regards.

 

Message 15 of 31
Anonymous
in reply to: Anonymous

Whoa! pretty slick! yes that gives all angles. Many thanks T. Willey! I have only had a quick look at it but it looks like you have made a temp point to find bearing, of a side. clever stuff....

Now I have a list of angles I guess the next step is to filter out the unwanted angles (ie greater than 180 degrees)

cheers Smiley Happy  Smiley Happy

 

Message 16 of 31
Anonymous
in reply to: Anonymous

You're welcome, and you are correct.  That is the only way I could think of to find if the angle found was for the inside of the polygon.

Message 17 of 31
Anonymous
in reply to: Anonymous

Hi T. Willey

sorry to bug you again!

I  did some more testing over the weekend and unfortunately I noticed that sometimes 'outside' angles are outputed

eg a rectangle would be (270 270 270 270 270) rather than the correct answer of (90 90 90 90 ). Also some angles are the "inside" angle while others are the outside angle. I have tried for several hours trying to fix this problem - but to no avail.

Other times it behaves correctly and gives the correct internal angles. I am not sure why this is happening?

I have now run out of ideas....

Solving the problem would be gratefully appreciated.

Message 18 of 31
Anonymous
in reply to: Anonymous

Thought something like that might happen when using the method I used.  You can check out this thread I started, after I gave you a solution, to see how some of the other minds did it.

 

http://www.theswamp.org/index.php?topic=36124.0

Message 19 of 31
Anonymous
in reply to: Anonymous

Hi,

 

I've been following this challenge, and I saw many and great solutions.

 

I'm also trying to develop a solution, but need help to develop a function.

 

I have a list of points (from verts), and I need to process the following:

 

 

 

 

;------------------------------------------------
;Sample - 6 sides closed pline (polygon)
(list p1 p2 p3 p4 p5 p6);list of points from verts
(angtos (- (- (angle p1 p2)(angle p2 p3)) pi));angle 1
(angtos (- (- (angle p2 p3)(angle p3 p4)) pi));angle 2
(angtos (- (- (angle p3 p4)(angle p4 p5)) pi));angle 3
(angtos (- (- (angle p4 p5)(angle p5 p6)) pi));angle 4
(angtos (- (- (angle p5 p6)(angle p6 p1)) pi));change here - angle 5
(angtos (- (- (angle p6 p1)(angle p1 p2)) pi));and here - angle 6
;------------------------------------------------
;Sample - 5 sides closed pline (polygon)
(list p1 p2 p3 p4 p5);list of points from verts
(angtos (- (- (angle p1 p2)(angle p2 p3)) pi))
(angtos (- (- (angle p2 p3)(angle p3 p4)) pi))
(angtos (- (- (angle p3 p4)(angle p4 p5)) pi))
(angtos (- (- (angle p4 p5)(angle p5 p1)) pi));change here
(angtos (- (- (angle p5 p1)(angle p1 p2)) pi));and here
;------------------------------------------------
;Sample - 4 sides closed pline (polygon)
(list p1 p2 p3 p4);list of points from verts
(angtos (- (- (angle p1 p2)(angle p2 p3)) pi))
(angtos (- (- (angle p2 p3)(angle p3 p4)) pi))
(angtos (- (- (angle p3 p4)(angle p4 p1)) pi));change here
(angtos (- (- (angle p4 p1)(angle p1 p2)) pi));and here
;------------------------------------------------
;Sample - 3 sides closed pline (polygon)
(list p1 p2 p3);list of points from verts
(angtos (- (- (angle p1 p2)(angle p2 p3)) pi))
(angtos (- (- (angle p2 p3)(angle p3 p1)) pi));change here
(angtos (- (- (angle p3 p1)(angle p1 p2)) pi));and here
;------------------------------------------------

 

 

The function should display the internal angles of polygon (closed pline).

 

Thanks in advance.

 

Rogerio 🙂

 

 

Message 20 of 31
Anonymous
in reply to: Anonymous

Thanks T. Willey - interesting ways of code. I am glad you posted the question on "The Swamp"

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

Post to forums  

AutoCAD Inside the Factory


Autodesk Design & Make Report