Jump to content

How to order a list of points of a closed polyline always in clockwise direction


Recommended Posts

Posted

Hi,

In a LISP routine I use this command to offset several closed polylines (simple line shapes, no arcs) to the outside of the closed polyline
 

 (vlax-invoke obj 'offset distance)))

 

If the distance is a positive value, the offset is performed to the outside (and a negative value to inside)
But "Outside/Inside" also depends on the direction in which the closed polyline is drawn.
If the closed polyline is drawn in counter clockwise direction and the offset distance value is positive, then the offset command wants to offset the polyline to the inside.
If this is the case AND the offset distance is set too large, the LISP function errors because it is not possible to create an offset with that distance to the inside (only to the outside).

The initial closed polylines which needs to be offset, are drawn from a LIST of coordinates
The order of the LIST with points of each closed polyline are either in clockwise or counter clockwise direction

 

Is it possible to re-order a LIST of points always in clockwise direction?


 

Posted

Just quickly some hints and will think about this shortly.

 

You can use reverse to alter reverse a list of points, or here http://www.theswamp.org/index.php?topic=50007.msg552346#msg552346

 

This might come in useful, working out where the centre of the shape is (setq p (osnap (vlax-curve-getStartPoint (entlast)) "gcen")) if you want to do some thinking but an internet search comes up with this thread https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/polyline-direction-clockwise-or-counterclockwise/td-p/6050612 which I think this is the good stuff::

 

  (defun ListClockwise-p (lst / z vlst)
    (vl-catch-all-apply 'minusp 
      (list
        (if 
          (not 
            (equal 0.0
              (setq z
                (apply '+
                  (mapcar 
                    (function
                      (lambda (u v)
                        (- (* (car  u) (cadr  v)) (* (car  v) (cadr  u)))
                      )
                    )
                    (setq vlst
                      (mapcar
                        (function
                          (lambda (a b) (mapcar '- b a))
                        )
                        (mapcar (function (lambda (x) (car lst))) lst) 
                        (cdr (reverse (cons (car lst) (reverse lst))))
                      )
                    )
                    (cdr (reverse (cons (car vlst) (reverse vlst))))
                  )
                )
              ) 1e-6
            )
          )
          z
          (progn
            (prompt "\n\nChecked vectors are colinear - unable to determine clockwise-p of list")
            nil
          )
        )
      )
    )
  )

 

 

  • Like 1
Posted (edited)

*Side-note About using gcen method. This didn't work so well with plots of land that shared borders with each other. I think it had to do with the draw order. But it sometimes it was picking the geo center of the adjacent plots so it wasn't 100% accurate.

 

This is what i used to check CW of a polyline. See example at start of lisp. will offset + or - depending on CW function.

;;----------------------------------------------------------------------------;;
; Checking if pline drawn CW or CCW - Writer Evgeniy Elpanov By Bill Gilliss
;(vla-offset (vlax-ename->vla-object entity) (if (CW entity) -0.01 0.01))
(defun CW (poly / lw lst LL UR)
  (setq lw (vlax-ename->vla-object poly))
  (vla-GetBoundingBox lw 'LL 'UR)
  (setq LL (vlax-safearray->list LL)
        UR (vlax-safearray->list UR)
        lst (mapcar
              (function
                (lambda (x)
                        (vlax-curve-getParamAtPoint poly
                                                    (vlax-curve-getClosestPointTo poly x)
                        )
                )
              )
              (list LL (list (car LL) (cadr UR))
                    UR (list (car UR) (cadr LL))
              )
            )
  )
  (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
    t
  )
)

 

--Edit

Another way is to offset with "both" option. Then check area of the polylines. tho if you have some funky shapes their could be more then two polylines created.

Edited by mhupp
  • Like 1
Posted (edited)

OK a very quick test on this:

 

Hatch the area and create the boundary, delete the hatch and retain the boundary. Offset that and delete the first created boundary? Selection is done by clicking inside the closed polyline - though haven't checked or tried to break this idea yet that might fix drawing order of polylines on top of each other. Quickly checking, the hatch boundary is always drawn clockwise..... again I need to check this

 

Lunch first though

 

 

 

 

This will do it.. if there is nothing within the closed polyline - not perfect because it is for quite specific case

 

(defun c:offsetoutside (/ ent dist obj)
  (vl-load-com)
  (princ "Pick a point inside the closed polyline shape")
  (command "-hatch" pause "")
  (setq myhatch (entlast))
  (command "-hatchedit" myhatch "b" "P" "N")
  (setq MyBoundary (entlast))
  (entdel myhatch)
  (setq dist (getreal "Enter Offset Distance"))
  (setq obj (vlax-ename->vla-object MyBoundary))
  (vla-offset obj dist)
)

 

Edited by Steven P
Posted
1 hour ago, Steven P said:

Just quickly some hints and will think about this shortly.

 

You can use reverse to alter reverse a list of points, or here http://www.theswamp.org/index.php?topic=50007.msg552346#msg552346

 

This might come in useful, working out where the centre of the shape is (setq p (osnap (vlax-curve-getStartPoint (entlast)) "gcen")) if you want to do some thinking but an internet search comes up with this thread https://forums.autodesk.com/t5/visual-lisp-autolisp-and-general/polyline-direction-clockwise-or-counterclockwise/td-p/6050612 which I think this is the good stuff::

 

  (defun ListClockwise-p (lst / z vlst)
    (vl-catch-all-apply 'minusp 
      (list
        (if 
          (not 
            (equal 0.0
              (setq z
                (apply '+
                  (mapcar 
                    (function
                      (lambda (u v)
                        (- (* (car  u) (cadr  v)) (* (car  v) (cadr  u)))
                      )
                    )
                    (setq vlst
                      (mapcar
                        (function
                          (lambda (a b) (mapcar '- b a))
                        )
                        (mapcar (function (lambda (x) (car lst))) lst) 
                        (cdr (reverse (cons (car lst) (reverse lst))))
                      )
                    )
                    (cdr (reverse (cons (car vlst) (reverse vlst))))
                  )
                )
              ) 1e-6
            )
          )
          z
          (progn
            (prompt "\n\nChecked vectors are colinear - unable to determine clockwise-p of list")
            nil
          )
        )
      )
    )
  )

 

 


I was already testing this sub function, but thanx anyway!
 

Posted

The sub function works perfectly i.c.w. a condition, Thanx for the hint!

Posted

This is what I use for CW CCW.

; 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))
  )
)
)

 

Posted
10 hours ago, BIGAL said:

This is what I use for CW CCW.

; 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))
  )
)
)

 

 

This is even a shorter code! Thanx for sharing, but my start is already a list of points of which I create the closed polylines.
In short: My main routine places a dynamical block of a jack-up vessel (which is used to install Monopiles for windfarms at sea) somewhere in the world (WCS) to check if the 4 legs (the closed  polylines) of the jack-up vessel don't conflict with restricted areas around the Monopile. If the dynamical block in a certain heading is inserted at the center point of the monopile, I need to offset those legs with a certain (safety) distance to check if one of them conflicts with a restricted area. So I have a subroutine which gets the WCS coordinates of the 4 legs of that block Instance in a list, of which we don't know if the list is CW/CCW ordered. And of course if we draw the legs inside the dynamical block already in the correct direction, this CW/CCW sub routine is not needed, but we have several Jack-up vessels and we are increasing and I don't want to bother my colleagues that they have to think about the drawing direction of the legs for new Jack-up Vessels because all 4 or 6 of them are symmetrical and therefor easy to mirror, which already causes the CW/CWW issue.

 

 

Posted (edited)

Pretty sure lee-mac submitted something that looks at 3 points and from angles determines CW or CCW.

Edited by BIGAL

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...