Community
style="PADDING-RIGHT: 0px; PADDING-LEFT: 5px; MARGIN-LEFT: 5px; BORDER-LEFT: #000000 2px solid; MARGIN-RIGHT: 0px">
"Bill Gilliss" <
href="mailto:bill@realerthanreal.com">bill@realerthanreal.com> wrote in
message
href="news:6095486@discussion.autodesk.com">news:6095486@discussion.autodesk.com...
Here's a 2D convex hull routine I spent an
enjoyable afternoon on. Draws an LWpolyline parallel to the WCS -- haven't yet
worked out just where to use (trans) to generate the hull parallel to other
UCS's.
-Bill
face="Courier New, Courier, monospace">;|
ConvexHull2D.lsp
draws,
parallel to the WCS, the 2D Least Convex Hull
of a set of POINTs, by the
wrapping method
by Bill Gilliss
bill dot gilliss at
aya.yale.edu
ver 1.0 Dec 24 2008 - initial release
Comments and
suggestions always welcome.
|;
(defun c:ConvexHull2D
( /
getPointList getBasePoint findSmallestAngle ptlist hullList pts
p1 p3
)
;;=====================================================
(defun
getPointList ( / n )
(setq ptlist nil hullList nil)
(prompt "Select points: ")
(setq pts (ssget '((0 .
"POINT"))))
(setq n 0)
(while (< n (sslength
pts))
(setq ptlist (cons (cdr (assoc 10 (entget (ssname
pts n)))) ptlist))
(setq n (1+ n))
)
)
;;=====================================================
(defun
getBasePoint ( / n en ed enx eny xmax ymax)
(setq n 0)
(while
(< n (sslength pts))
(setq en (ssname pts
n)
ed (entget
en)
enx (cadr
(assoc 10 ed))
eny
(caddr (assoc 11
ed))
)
(if (= n 0)
(setq basepoint en xmax
enx ymax eny)
(if
(> enx
xmax)
(setq
basepoint en xmax enx ymax
eny)
(if
(and (equal enx
xmax)
(> eny
ymax)
)
(setq basepoint en xmax enx ymax
eny)
);if
);if
);if
(setq n (1+ n))
);while
(setq basepoint (cdr (assoc 10 (entget
BasePoint))))
(setq p1 basepoint)
(setq p3
nil)
)
(defun findSmallestAngle ( / n p2 smallestAng)
(setq smallestAng (* 2 pi))
(setq n 0)
(while
(< n (length ptlist))
(setq p2 (nth n ptlist))
(if
(and
(not (equal p1
p2))
(not (member p2
hullList))
)
(progn
(setq ang (angle (trans
p1 0 1) (trans p2 0 1)))
(if
(and
(< ang
smallestAng)
(not (equal ang 0.0
1e-12))
)
(setq
smallestAng ang p3
p2)
)
)
)
(setq n (1+
n))
);while
)
;;============================================
(defun
makePolyline ()
(setq polylist
(list
'(0 . "LWPOLYLINE")
'(100 . "AcDbEntity")
'(100 .
"AcDbPolyline")
(cons 90 (length
hullList))
'(70 .
1)
)
)
(setq vtxlist (mapcar '(lambda (coord)
(cons 10 coord)) hullList))
(setq Polylist (append Polylist
vtxList))
(entmake PolyList)
)
;;=====================================================
(command "._undo" "_begin")
(if (tblsearch "UCS" "ConvexHull2D")
(command "._UCS" "_save" "ConvexHull2D"
"_y")
(command "._UCS" "_save"
"ConvexHull2D")
)
(getPointList)
(getBasePoint)
(setq *ucsicon (getvar
"ucsicon"))
(setvar "ucsicon" 0)
(while (not
(equal basepoint p3))
(findSmallestAngle)
(setq hullList (cons p3
hullList))
; (command "line" (trans p1 0 1) (trans p3 0
1) "")
(command "ucs" (trans p3 0 1) (trans p1 0
1) "")
(setq p1 p3)
);while
(makePolyline)
(setvar "ucsicon" *ucsicon)
(command "._UCS" "_restore" "ConvexHull2D")
(command "._UCS"
"_delete" "ConvexHull2D")
(command "._undo"
"_end")
);defun
(defun c:ch2d ()
(c:ConvexHull2d))
(princ "ConvexHull2D loaded. Enter CH2D to
run.")
(princ)
Hi Bill,
Thanks for sharing. I just copied
your code into the Vlide, loaded it, and typed CH2D at the command
line. It asked me to select points so I selected by the Window
method. It crashed. I ascertained (Last Break Source) the problem
was somewhere in the following line:
(command "ucs" (trans p3 0 1) (trans
p1 0 1) "")
style="PADDING-RIGHT: 0px; PADDING-LEFT: 5px; MARGIN-LEFT: 5px; BORDER-LEFT: #000000 2px solid; MARGIN-RIGHT: 0px">
"Bill Gilliss" <
href="mailto:bill@realerthanreal.com">bill@realerthanreal.com> wrote in
message
href="news:6095544@discussion.autodesk.com">news:6095544@discussion.autodesk.com...
Fatfreek wrote:
Hi Bill,
Thanks for sharing. I just copied your
code into the Vlide, loaded it, and typed CH2D at the command line. It
asked me to select points so I selected by the Window method. It
crashed. I ascertained (Last Break Source) the problem
was somewhere in the following line:
(command "ucs" (trans p3 0 1) (trans p1 0 1)
"")
Thanks for the feedback.
Here
is a much faster and more reliable version: (command "UCS" ...) calls
have been eliminated and point list pruning has upped performance by about 4x.
5000 points in just over 2 seconds. Not too shabby.
I still need
to localize the variables and add error handling, but it is pretty unobtrusive
code -- only plays with cmdecho.
I've been testing it hard all evening
(note to self: get a life!), so now it is your turn. Let me know how it
goes.
-Bill
face="Courier New, Courier, monospace">;|
ConvexHull2D.lsp
draws the
Least Convex Hull of a set of POINTs as a 2D polyline
in the *current*
UCS.
by Bill Gilliss
bill dot gilliss at aya.yale.edu
ver 1.0 Dec
25 2008 - initial release
Notes:
- The routine will generate
different hulls for different UCS's, so is
most useful when in PLAN view for the current UCS.
- Points may be
2D or 3D - Z coordinate is ignored. Polyline is drawn
in
current XY plane.
- Uses the
wrapping method, starting from the farthest right point.
- Pruning
that eliminates most interior points before analysis results
in
approx 4x speed increase.
Comments
and suggestions always
welcome.
|;
;;=====================================================
(defun
getPointList ( / n )
(setq ptlist nil hull nil)
(prompt
"Select points: ")
(setq pts (ssget '((0 . "POINT"))))
(setq n 0)
(while (< n (sslength pts))
(setq pt (cdr (assoc 10 (entget (ssname pts n)))))
(setq
pt (trans pt 0 1))
(setq pt (list (car pt) (cadr
pt)))
(setq ptlist (cons pt
ptlist))
(setq n (1+ n))
)
)
;;=====================================================
(defun
getNEWSPoints ( / n en ed enx eny xmax ymax)
(setq n 0)
(setq pt (nth n ptlist) ptx (car pt) pty (cadr pt))
(setq eastPt
pt
xmax
ptx
ymax
pty
xmin
ptx
ymin pty)
(setq n 1)
(while
(< n (length
ptlist))
(setq pt (nth n ptlist) ptx (car pt) pty (cadr
pt))
(if (> ptx
xmax)
(setq EastPt pt xmax
ptx)
(if (< ptx
xmin)
(setq
WestPt pt xmin
ptx)
)
)
(if (> pty
ymax)
(setq NorthPt pt ymax
pty)
(if (< pty
ymin)
(setq SouthPt pt ymin
pty)
)
)
(setq n (1+
n))
);while
)
(defun findMinAngle ( / n p2 ang
minAng )
(setq p3 temp)
(setq
minAng 2pi n 0)
(while ;;optimize this loop as
much as possible
(< n (length
ptlist))
(setq p2 (nth n
ptlist))
(if (not (equal p2
p1))
(progn
(setq ang
(rem (+ 2pi (angle p1 p2) (- prevang))
2pi))
(if (and (<
ang minAng) (not (equal ang 0.0
1e-12)))
(setq minAng ang p3 p2
)
)
)
)
(setq n (1+
n))
);while
(setq hull (cons p3
hull))
(setq prevang (angle p3
p1))
(command "._line" p1 p3
"")
(ssadd (entlast)
lines)
(setq temp p1 p1
p3)
)
(defun prunePoints ( / NP SP EP WP p1 p2 p3)
(setq
NP northPt EP eastPt WP westPt SP southPt)
(setq
NEWSpts (list NP EP WP SP))
;;prune north
half
(setq p1 EP p2 NP p3 WP)
(prune)
;;prune south half
(setq p1 WP p2 SP
p3 EP)
(prune)
(if (or (equal EP
NP)
(equal NP
WP)
(equal WP
SP)
(equal SP
EP)
)
(progn
;;prune west
half
(setq p1 NP p2 WP p3 SP)
(prune)
;;prune east half
(setq p1 SP p2 EP p3
NP)
(prune)
);progn
);if
)
(defun prune ()
(if (and (/= p1 p2) (/= p2
p3))
(progn
(setq
TriangleArea (area3p p1 p2 p3))
(foreach pt
ptlist
(progn
(setq
testArea
(+
(area3p p1 p2
pt)
(area3p p2 p3
pt)
(area3p p3 p1
pt)
)
)
(if
(and
(not (member pt
NEWSpts))
(equal testArea TriangleArea
1e-8)
)
(setq
ptlist (vl-remove pt
ptlist))
)
);progn
)
);progn
);if
)
(defun area3p (p1 p2 p3 / a b c s)
(setq
a (distance p1
p2)
b (distance p2
p3)
c (distance p3
p1)
s (* 0.5 (+ a b
c))
)
(sqrt
(*
s
(- s a)
(- s b)
(- s c)
)
)
)
;;=========== main routine
=========================
(defun c:ConvexHull2D () ;( / ptlist hull pts p1
p3 2pi)
(setq 2pi (* 2 pi))
(setq *cmdecho (getvar
"cmdecho"))
(setvar "cmdecho" 0)
(command "._undo"
"_begin")
(setq hull nil)
(setq lines (ssadd))
(getPointList)
(getNEWSPoints)
(setq startTime (*
86400 (getvar "tdusrtimer")))
(prunePoints)
(setq
p1 eastPt)
(setq hull (cons p1 hull))
(setq p3 (list (car
p1) (1- (cadr p1))) temp p3)
(setq prevang (angle p1
p3))
(while (not (equal p3 eastPt)) ;;i.e., continue until
closure
(findMinAngle)
);while
(setq endTime (* 86400 (getvar "tdusrtimer")))
(command "pedit" (entlast) "_join" lines "" "_x")
(command
"._redraw")
(command "._undo" "_end")
(setvar "cmdecho"
*cmdecho)
(princ (strcat "elapsed time: " (rtos (- endtime
startTime))))
(princ)
);defun
(defun c:ch2d ()
(c:ConvexHull2d))
(princ "ConvexHull2D loaded. Enter CH2D to
run.")
(princ)
Bill,
This is my 3rd try at responding.
This time, I won't attach the drawing (the server may be rejecting it)
of scattered points.
Your routine draws single lines
through the outermost points, then halts at the following line:
(command "pedit" (entlast) "_join"
lines "" "_x")
Len
style="PADDING-RIGHT: 0px; PADDING-LEFT: 5px; MARGIN-LEFT: 5px; BORDER-LEFT: #000000 2px solid; MARGIN-RIGHT: 0px">
"Bill Gilliss" <
href="mailto:bill@realerthanreal.com">bill@realerthanreal.com> wrote in
message
href="news:6095635@discussion.autodesk.com">news:6095635@discussion.autodesk.com...
Fatfreek wrote:
Bill,
This is my 3rd try at responding. This time, I
won't attach the drawing (the server may be rejecting it) of scattered
points.
Your routine draws single lines through the
outermost points, then halts at the following line:
(command "pedit" (entlast) "_join" lines ""
"_x")
Len
Len
-
One more time -- we must have different setting for PEDITACCEPT. The
attached should take care of that.
-
Bill
Bill,
It went through without a hitch this
time, producing a polyline that connected points on the periphery of a
pattern of points.
Not knowing what your scheme is, it
appears that it can be likened to a board with a bunch of pins
protruding; then taking a string and simply wrapping that string
around the outermost pins. Is that a correct assessment?
Len