Match direction of all polylines

Match direction of all polylines

Anonymous
Not applicable
3,465 Views
11 Replies
Message 1 of 12

Match direction of all polylines

Anonymous
Not applicable

This is my first post to the Autodesk forums so I apologize if I have not selected the correct category.

I am currently working with Autodesk Civil 3D 2020

 

I was wondering if there was any way, either in CAD or via a LISP command, that I could change the direction of all of the polylines in my drawing to either run clockwise or counterclockwise. It is similar to the Reverse command already available in the Polyline Edit commands, however I would like all of the lines to run the same direction.

 

The reason being I have recently installed a dynamic offset LISP which allows me to offset multiple lines a specific distance, however if the lines are not all running the same direction then the offset will not be placed on the side I would like. 

Thanks in advance for any information!

0 Likes
Accepted solutions (1)
3,466 Views
11 Replies
Replies (11)
Message 2 of 12

Kent1Cooper
Consultant
Consultant
Accepted solution

If it's a matter of inward vs. outward, on things with area  [not, for example, a single-line-segment  Polyline], you could use OffsetInOrOut.lsp, with its OffIn and OffOut commands, >here<.  It doesn't reverse things, but tries Offsetting in one direction on each selected object, and if the result is to the wrong side [e.g. if it's bigger than the original if you wanted to Offset inward], eliminates that and goes the other way.  See comments in that thread and in the file.  [Message 28 on the same thread has a version that puts the results on the Current Layer.]

 

If that doesn't suit you, and you do need to reverse the direction of some objects, there are lots of threads here involving the question of whether something runs clockwise or counterclockwise -- do some Searching, and very likely you'll find something you can use.

Kent Cooper, AIA
Message 3 of 12

hak_vz
Advisor
Advisor

Here you have a quick solution that converts all lwpolylines to counterclockwise direction. If you find this applicable select this as a solution.

 

(defun revlwpline (e / footer done vertices header flag)
  ;reverse lightweight polyline
  ;http://www.metzgerwillard.us/tdavis/lisp/reverse.html
  (foreach item (reverse (entget e))
    (cond
      ((not done)
        (cond
          ((= (car item) 40)
            (setq footer (cons (cons 41 (cdr item)) footer)      ;swap width
                  done t
            )
          )
          ((= (car item) 41)
            (setq footer (cons (cons 40 (cdr item)) footer))     ;swap width
          )
          ((= (car item) 42)
            (setq footer (cons (cons 42 (- (cdr item))) footer)) ;negate bulge
          )
          ((= (car item) 210)
            (setq footer (cons item footer))
          )
        )
      )
      ((= (car item) 10)
        (setq vertices (cons item vertices))
      )
      ((= (car item) 40)
        (setq vertices (cons (cons 41 (cdr item)) vertices))     ;swap width
      )
      ((= (car item) 41)
        (setq vertices (cons (cons 40 (cdr item)) vertices))     ;swap width
      )
      ((= (car item) 42)
        (setq vertices (cons (cons 42 (- (cdr item))) vertices)) ;negate bulge
      )
      (t (setq header (cons item header)))
    )
  )
  (setq flag (assoc 70 header))
  (if (< (cdr flag) 128)                 ;turn on linetype generation
    (setq header (subst (cons 70 (+ (cdr flag) 128)) flag header))
  )
  (entmod (append header (reverse vertices) footer))
  (princ)
)

(defun to_counter_clockwise ( e / LW LST MAXP MINP)
; Writer Evgeniy Elpanov.
; modified by hak_vz
  (setq lw (vlax-ename->vla-object e))
  (vla-GetBoundingBox lw 'MinP 'MaxP)
  (setq
      minp (vlax-safearray->list minp)
      MaxP (vlax-safearray->list MaxP)
      lst 
        (mapcar
          (function
          (lambda (x)
          (vlax-curve-getParamAtPoint
          lw
          (vlax-curve-getClosestPointTo lw x)
          ) ;_ vlax-curve-getParamAtPoint
          ) ;_ lambda
          ) ;_ function
          (list minp
               (list (car minp) (cadr MaxP))
                MaxP
               (list (car MaxP) (cadr minp))
                ) ;_ list
          ) ;_ mapcar
      ) ;_ setq
  (if 
    (or
      (<= (car lst) (cadr lst) (caddr lst) (cadddr lst))
      (<= (cadr lst) (caddr lst) (cadddr lst) (car lst))
      (<= (caddr lst) (cadddr lst) (car lst) (cadr lst))
      (<= (cadddr lst) (car lst) (cadr lst) (caddr lst))
     ) ;_ or
        (revlwpline e)
    ) ;_ if

) ;_ defun


(defun c:all_lwpolcw ( / ss i )
(setq ss (ssget "X" '((0 . "lwpolyline"))) i 0)
(while (< i (sslength ss))
(to_counter_clockwise (ssname ss i))
(setq i (+ i 1))
)
(princ)
)
(princ "\nCommand all_lwpolcw converts all lwpolylines to counterclockwise direction")
(princ)

 

 

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 4 of 12

Kent1Cooper
Consultant
Consultant

@hak_vz wrote:

Here you have a quick solution that converts all lwpolylines to counterclockwise direction. ....


It seems to me that it should not be necessary to have that revlwpline routine now that the REVERSE command exists [the routine was likely written before it did].  It should only be necessary to determine the drawn direction of a Polyline, and if it's not drawn in the desired direction, apply REVERSE to it.

Kent Cooper, AIA
0 Likes
Message 5 of 12

hak_vz
Advisor
Advisor

I agree, it can be changed with command REVERSE.

Miljenko Hatlak

EESignature

Did you find this post helpful? Feel free to Like this post.
Did your question get successfully answered? Then click on the ACCEPT SOLUTION button.
0 Likes
Message 6 of 12

Anonymous
Not applicable

This was exactly what I was trying to do, thanks for pointing me in the right direction.

0 Likes
Message 7 of 12

Sea-Haven
Mentor
Mentor

Pretty sure this was done by pbe, a nice check area of pline if -ve then you would use the reverse command, very simple.

 

 

 

;; get closed polygon's area

(defun ss-pts2area  (l)
(/ (apply (function +)
            (mapcar (function (lambda (x y)
                                (- (* (car x) (cadr y)) (* (car y) (cadr x)))))
                    (cons (last l) l)
                    l)) 
2.)
)

 ;_force pointset CCW
(setq plent (entsel "\nPick pline"))
(setq co-ord (mapcar 'cdr (vl-remove-if-not '(lambda (x) (= (car x) 10)) (entget (car plent)))))

(if (< (ss-pts2area co-ord) 0)
(command "reverse" plent "")
)

 

 

 

 

0 Likes
Message 8 of 12

Kent1Cooper
Consultant
Consultant

@Sea-Haven wrote:

.... check area of pline if -ve then you would use the reverse command, very simple.


... and, unfortunately, very wrong  if the Polyline in question contains any arc segment(s).  Not only can it be wrong about the area, but also about the sign  of the area, i.e. the drawn direction.  Here are two Polylines of exactly the same shape, both drawn in the clockwise direction starting at point A.  The red one on the left has a single arc segment from A around to B; the green one on the right does that curve with two arc segments from A to C, with B as a vertex midway.

PolylineAreas.PNG

The "areas" reported by  (ss-pts2area co-ord)  are indicated below.  They are actually the areas of the line-segment-only  shapes shown in dashed white with hatching inside.  Notice not only that they differ from the real area of the Polylines [both 2.202322] and from each other, but also that one is positive and one negative, though the Polylines were drawn in the same direction.  That's because on the left, it looks from A to B directly, without accounting for the Polyline's actual route swinging around the far side.  So something that decides whether to REVERSE a Polyline based on that routine's result would do it to one of these but not the other, and (vla-offset) with the same sign on its offset distance would go the wrong way from one of them.

 

The OffIn and OffOut commands work correctly with situations like these, because their area comparison accounts for arc segments.  They also work with open  Polylines, as well as with other kinds of objects with area [Arc, Circle, Ellipse, Spline].

Kent Cooper, AIA
0 Likes
Message 9 of 12

Sea-Haven
Mentor
Mentor

Thanks for the hint. As you say method only uses vertices. So single arc is ignored. Would need to add a midpoint on bulges. Not worth the effort.

 

A suggestion if for only checking CW or CCW then could use bounding box and a fuzz factor for offset so no user input required. Like everything need some time to have a go.

0 Likes
Message 10 of 12

Kent1Cooper
Consultant
Consultant

@Sea-Haven wrote:

.... Like everything need some time to have a go.


I wouldn't bother -- spend the time Searching this Forum, where this has come up many times before, and you'll find a whole variety of approaches to the problem.

Kent Cooper, AIA
0 Likes
Message 11 of 12

Sea-Haven
Mentor
Mentor

Did it any way so I would have a solution in my tool chest.

 

; Checking if pline is CW or CCW and set to CCW
; Orignal idea  by Kent Cooper, 1 August 2018 Offsetinorout.lsp
; By Alan H July 2020

(defun AH:chkcwccw (ent / objnew area1 area2 obj minpoint maxpoint)

(setq obj (vlax-ename->vla-object ent))
(vla-GetBoundingBox obj 'minpoint 'maxpoint)
(setq pointmin (vlax-safearray->list minpoint))
(setq pointmax (vlax-safearray->list maxpoint))
(setq dist (/ (distance pointmin pointmax) 20.0))

(vla-offset obj dist)
(setq objnew (vlax-ename->vla-object (entlast)))
(setq area1  (vlax-get objnew 'Area))
(vla-delete objnew)

(vla-offset obj (- dist))
(setq objnew (vlax-ename->vla-object (entlast)))
(setq area2  (vlax-get objnew 'Area))
(vla-delete objnew)

(if (> area1 area2)
  (progn
  (command "reverse" ent "")
  (setq y (+ y 1))
  )
)
)

(defun c:CWCCW   ( / *error*  x ent oldsnap doc ss)

(setq doc (vla-get-activedocument (vlax-get-acad-object)))

(vla-startundomark doc)
(setq y 0)
(setq oldsnap (getvar 'osmode))
(setvar 'osmode 0)

(prompt (strcat "\nSelect Plines to check"))

(if (setq ss (ssget  '((0 . "*POLYLINE"))))
    (progn
      (repeat (setq x (sslength ss))
         (setq ent (ssname ss (setq x (- x 1))))
         (AH:chkcwccw ent)
      )
   )
)
(vla-endundomark doc)

(alert (strcat (rtos y 2 0) " Plines reversed"))

(setvar 'osmode oldsnap)
(princ)
)

(vl-load-com)
(prompt "\nType CWCCW to set plines to CCW")
(c:CWCCW)
0 Likes
Message 12 of 12

john.uhden
Mentor
Mentor

Here's my method for determining if a polyline is CW or CCW (use the @polydir function)

 

    (defun @Anonymous (a1 a2)
      (cond
        ((> a1 (+ a2 pi))
          (+ a2 pi pi (- a1))
        )
        ((> a2 (+ a1 pi))
          (- a2 a1 pi pi)
        )
        (1 (- a2 a1))
      )
    )

   ;; Function to group a list of items into a list of
   ;; multiple lists, each of length N, e.g.
   ;; '(A B C D E F G H I) -> '((A B C)(D E F)(G H I))
   (defun @group (lst n / item new)
     (foreach element (reverse lst)
       (setq item (cons element item))
       (if (= (length item) n)
         (setq new (cons item new) item nil)
       )
     )
     new
   )

  ;; Function to return the polyline direction based on the sum of
  ;; the deflections from vertex to vertex:
  ;; Argument:
  ;;    object = vla-object (POLYLINE or LWPOLYLINE)
  (defun @polydir (object / e ent etype coords flag i p1 p2 p3 sum)
    (setq e      (vlax-vla-object->ename object)
          ent    (entget e)
          etype  (cdr (assoc 0 ent))
          flag   (cdr (assoc 70 ent))
          coords (vlax-get object 'Coordinates)
          i 1
          sum 0.0
    )
    (if (= etype "LWPOLYLINE")
      (setq coords (@group coords 2))
      (setq coords (@group coords 3))
    )
    (if (= (logand 1 flag) 1) ; closed
      (setq coords (reverse (cons (car coords)(reverse coords))))
    )
    (repeat (- (length coords) 2)
      (setq p1  (nth (1- i) coords)
            p2  (nth i coords)
            i   (1+ i)
            p3  (nth i coords)
            sum (+ sum (@delta (angle p1 p2)(angle p2 p3)))
      )
    )
    (if (minusp sum) "CW" "CCW")
  )

 

John F. Uhden

0 Likes