Polyline total lisp: Issues with rotation angle

Polyline total lisp: Issues with rotation angle

kylecanario
Explorer Explorer
570 Views
4 Replies
Message 1 of 5

Polyline total lisp: Issues with rotation angle

kylecanario
Explorer
Explorer

Hello I was wondering if anyone can help me with a section of my lisp. I wrote a lisp that will: prompt the user to select polylines on a certain layer, specify what type of line it is, specify scale of the block,  gets the total vertices of each polyline, gets the total length of the polyline, and then places a block at the midpoint of vertices 1 and 2 with the total footage and offsets it by 4. My problem is getting the correct rotation angle for each polyline. Polylines that are drawn from left to right are correct. Any polyline that is drawn from right to left is either upside-down or not anywhere close to the midpoint of vertices 1 and 2. See the uploaded screenshot as a reference. 

 

(defun c:Crossing (/ UserLayer TrenchType TxtScale pl plObj vts pt1 pt2 CrossingDist ang blkoffset midptoffset angstr FootageTick tlen tlenTick)
 
(setq UserLayer (getvar "CLAYER"))
 
(setvar "CLAYER" "K-TRSECT$")
 
(setvar "ATTDIA" 0)
 
(initget "M1 P1")
 
(setq TrenchType (strcase (getstring "\nSpecify crossing type: [M1/P1]? ")))
 
(cond
 
  ((= "M1" TrenchType)
 
   (setq TrenchType "M1"))
 
   ((= "P1" TrenchType)
 
     (setq TrenchType "P1"))
 
  ((= "M" TrenchType)
 
   (setq TrenchType "M1"))
 
   ((= "P" TrenchType)
 
     (setq TrenchType "P1"))
  )
 
(initget "20 30")
 
(setq TxtScale (getstring "\nDetermine the scale of your crossing text: [20/30] scale "))
 
(cond
 
  ((= "2" TxtScale)
 
   (setq TxtScale "2.5"))
 
   ((= "3" TxtScale)
 
     (setq TxtScale "3.5"))
 
  ((= "20" TxtScale)
 
   (setq TxtScale "2.5"))
 
   ((= "30" TxtScale)
 
     (setq TxtScale "3.5"))
 
  )
 
(setq pl (ssget '((0 . "LWPOLYLINE") (8 . "K-XING"))))
 
(if pl
 
(progn
 
(setq e 0)
 
(repeat (sslength pl)
 
(setq ent (ssname pl e))
 
(setq plObj (vlax-ename->vla-object ent))
 
(setq vts (mapcar 'cdr (vl-remove-if-not '(lambda (x) (vl-position (car x) '(10 11))) (entget ent))))
 
(setq pt1 (car vts))
 
(setq pt2 (cadr vts))
 
(setq CrossingDist (distance pt2 pt1))
 
(if (< (car pt1) (car pt2))
 
(setq ang (angle pt1 pt2))
 
(setq ang (- (angle pt2 pt1)))
 
) ;end ang if
 
(setq blkoffset 4)
 
(setq midptoffset (polar (polar pt1 ang (/ CrossingDist 2)) (+ ang (/ pi 2)) blkoffset))
 
(setq angstr (angtos ang))
 
(setq FootageTick "'")
 
(setq tlen (vla-get-length plObj))
 
(setq tlen (fix (+ tlen (if (minusp tlen) -0.5 0.5))))
 
(setq tlen (rtos tlen))
 
(setq tlenTick (strcat tlen FootageTick))
 
(command "-insert" "K-SEC" "s" TxtScale midptoffset angstr TrenchType tlenTick "")
 
(setq e (1+ e))
 
) ;end repeat
 
) ;end progn
 
(prompt "\nNo Crossings have been selected")
 
) ;end first if
 
(setvar "CLAYER" UserLayer)
 
    (setvar "ATTDIA" 1)
 
(princ)
 
 
) ;end defun
0 Likes
571 Views
4 Replies
Replies (4)
Message 2 of 5

devitg
Advisor
Advisor

@kylecanario Please upload your sample.dwg

0 Likes
Message 3 of 5

Kent1Cooper
Consultant
Consultant

It has to be a combination of these two things:

 

(if (< (car pt1) (car pt2))
  (setq ang (angle pt1 pt2))
  (setq ang (- (angle pt2 pt1)))
) ;end ang if
 
and
 
(setq midptoffset (polar (polar pt1 ang (/ CrossingDist 2)) (+ ang (/ pi 2)) blkoffset))
 
Your image does not indicate in which direction anything was drawn, and it shows incorrect results only at horizontal segments.  What happens with a diagonal or vertical first segment?  [I will let you find out.]
 
In a horizontal first segment drawn from right to left, (< (car pt1) (car pt2)) will return nil, so ang will be set to (- (angle pt2 pt1)).  But (angle pt2 pt1) will be zero, and the negative of that will also be zero, which explains both your misplaced Blocks -- they're at 0° from pt1 by what looks like the appropriate distance.  In such a case, the red pt1 above [the base point of the (polar) function] should be pt2 instead.
 
I think [without experimentation] that while you may want something like your ang setting for the rotation angle of the Block, for the first angle argument in setting midptoffset to determine the insertion point of it relative to pt1, you want not ang but only (angle pt1 pt2)  [never negative] regardless of in which direction it's drawn.
Kent Cooper, AIA
0 Likes
Message 4 of 5

Sea-Haven
Mentor
Mentor

Another is you can get angle at a point on a pline so can check this and use is text readable to change angle. I use a lee-mac readable lisp.

 

(defun alg-ang (obj pnt)
  (angle '(0. 0. 0.)
     (vlax-curve-getfirstderiv
       obj
       (vlax-curve-getparamatpoint
         obj
         pnt
       )
     )
  )
)


;; Make Readable  -  Lee Mac
  ;; Returns a given angle corrected for text readability
(defun lm:makereadable (a)
    ((lambda (a)
       (if (and (< (* pi 0.5) a) (<= a (* pi 1.5)))
	 (+ a pi)
	 a
       )
     )
      (rem (+ a pi pi) (+ pi pi))
    )
)

 

 

0 Likes
Message 5 of 5

john.uhden
Mentor
Mentor

@Sea-Haven ,

That's the right idea but Lee-Mac's function is overdone.

This is simpler:

(defun makereadable (a)
  (if (< (* pi 0.5) a (* pi 1.5))
    (+ a pi)
    a
  )
)
;; because AutoCAD doesn't stumble on angles > 2pi

Of course it would be best if the text were aligned middle+center so that it's position doesn't change.

As to being above or below the polyline segment, it's easy if Plan;World (just check the Y values), but if the view is twisted it requires some additional math, which though I've done a hundred times I'd have to figure it out all over again, being it's now 20-30 years later.

John F. Uhden

0 Likes