Jump to content

3dpolyline from list


Mark Ca

Recommended Posts

Hello world!

 

Im making a program to "shrinkwrap" a set of points selected by the user. It asks for 2 seed points and selects the next by a combination of distance and angle. I will post it when done in case anyone else would find it useful.

 

I have a couple little snags though as i'm new to autolisp coding.

 

How would I output the data as a polyline on the current layer? I have it stored now as a list eg.

Command: !pointsxyz

((-48.5079 -0.709823 0.0) (-46.3576 4.23851 0.0) (-43.3432 14.1435 0.0)

(-38.6845 11.4073 0.0) (-48.5079 -0.709823 0.0))

 

I could do entmake but then how do I specify to make it on current layer?

 

 

Also I got stuck with filtering the user's point selection window to only points.

(setq points (ssget _W))

 

And lastly is there a neat way to compare check if one point has the same coordinates as another? Directly comparing does not seem to work, I assume it only compares a reference to the coordinates.

 

Many thanks for reading, and happy coding!

Link to comment
Share on other sites

Welcome to Cadtutor .

 

You can make entmake and include the codes to follow the layer name eg. (cons 8 "YourLayerName") or make the needed layer current which would

normally let the entmake lay the entity on it .

 

Filtering for points only ;

 

(setq pts (ssget '((0 . "POINT"))))

 

Regards.

 

Tharwat

Link to comment
Share on other sites

Awesome, thank you, I didn't realize that would still prompt the user for a selection window without the W.

 

I'm very confused about how entmake works actually. Why does

 

(entmake

'(

(0 . "LINE")

(10 0 0 0)

(11 1 1 0)

)

)

work, but

(setq x (10 0 0 0))

(entmake

'(

(0 . "LINE")

(x)

(11 1 1 0)

)

)

doesn't?

 

 

 

Another confusing bit still was that the following returns nil

(setq points (ssget '((0 . "POINT"))))

(= (entget (ssname points 0)) (entget (ssname points 0)))

 

Cheers!

Mark

Link to comment
Share on other sites

Wouldn,t it be easier to do something like

 

(setq x (length ptsxyz))

(setq y 0)

(command "pline")

(repeat x

(command (nth y ptsxyz))

(setq y (+ y 1))

)

(command "")

Link to comment
Share on other sites

This is way that it goes with entmake ..

 

(entmake
(list
(cons 0 "LINE")
(cons 10 '(0. 0. 0.))
(cons 11 '(1. 1. 0.))
)
) 

 

And for your second confusion , hope this what you mean .

 

(setq points (ssget '((0 . "POINT"))))
(= (cdr (assoc 0 (entget (ssname points 0)))) "POINT")

 

Regards

Link to comment
Share on other sites

I'm very confused about how entmake works actually.

 

That trouble-maker excerpt of code has some syntax errors; please find below the fixes for your original code:

 

(setq x [color=red]'[/color](10 0 0 0))

(entmake
([color=red]list[/color]
 [color=red]'[/color](0 . "LINE") 
 x
 [color=red]'[/color](11 1 1 0) 
)
)

 

Regards,

Mircea

Link to comment
Share on other sites

Another confusing bit still was that the following returns nil

(setq points (ssget '((0 . "POINT"))))

(= (entget (ssname points 0)) (entget (ssname points 0)))

 

Look into the (eq) function for comparing enames

 

-David

Link to comment
Share on other sites

I'm very confused about how entmake works actually.

 

Hi Mark,

 

This is not a difference in the behaviour of the entmake function, but rather how the list argument supplied to entmake is evaluated.

 

This should help with your understanding:

http://www.cadtutor.net/forum/showpost.php?p=258390&postcount=20

 

If you still have questions, please ask.

Link to comment
Share on other sites

This might help...

 

  (defun _pline (lst)
   (if (and (> (length lst) 1)
            (entmakex '((0 . "POLYLINE") (10 0. 0. 0.) (70 . ))
            (foreach x lst (entmakex (list '(0 . "VERTEX") (cons 10 x) '(70 . 32))))
       )
     (cdr (assoc 330 (entget (entmakex '((0 . "SEQEND"))))))
   )
 )

Link to comment
Share on other sites

You guys are AMAZING! Very helpful says the new guy struggling to learn Autolisps.

 

If anyone is interested, here is my code to connect a selection of points into a box. It finds the centroid then selects the next point based on the smallest angle between the previous point and centroid to new point (uses cal ang requiring a normal vector). So all the points need to lay on a plane in 3d.

 

It then makes a 3dpolyline from the point list created.

 

I might modify it to have the user select a few 'centroids' and compare the angle between the previous point and the closest centroid to find the next point. Just to be able to handle more awkward shapes.

 


;Connects selected points into a box, finds next points by angle from last point to new
;point through centroid of all points. All points must lay on the same plane in 3d space. 
;Mark Camball, March 2010
(defun c:p2b ();/ points length centroid p list_pt previousp i)

;;;;;;;;;;;;;;FIND CENTROID OF POINTS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun centroid(sspoints / sumx sumy sumz z)
(setq length (sslength points))
(setq sumx 0 sumy 0 sumz 0 z 0)
(repeat length
 (setq sumx (+ sumx (car (cdr (assoc 10 (entget (ssname points z)))))))
 (setq sumy (+ sumy (cadr (cdr (assoc 10 (entget (ssname points z)))))))
 (setq sumz (+ sumz (caddr (cdr (assoc 10 (entget (ssname points z)))))))
 (setq z (+ 1 z))
);_repeat
(setq sumx (/ sumx length) sumy (/ sumy length) sumz (/ sumz length) )
(list sumx sumy sumz)
);_centroid
;(setq sum '(0,0,0))? and add to list instead of 3 counters?
;;;;;;;;;;;;;;GET NORMAL VECTOR;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun norm(sspoints / pt1 pt2 pt3)
(setq pt1 (cdr (assoc 10 (entget (ssname points 0)))))
(setq pt2 (cdr (assoc 10 (entget (ssname points 1)))))
(setq pt3 (cdr (assoc 10 (entget (ssname points 2)))))
(cal "nor(pt1,pt2,pt3)")
);_norm
;error if not all points on same plane or duplicate points chosen
;;;;;;;;;;;;DETERMINES THE NEXT POINT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun nextpoint( / amin n p2 acur pm)
 (setq amin 500);loop makes this lower every time a lower value is found 

 (setq n 0)
 (repeat length ;loop through all the points and save the next point to pm
  ;gets the coordinates from the nth point in selection set
  (setq p2 (cdr (assoc 10 (entget (ssname points n)))))
  
  ;if the new point is not same as the last point made
  (if (not (equal previousp p2))  (progn
   ;set angle from lead point to centroid to point in question (3d angle needs normal vector p)
   (setq acur (cal "ang(centroid,previousp,p2,p)"))
    
   ;if the angle is lowest found while looping through all points, make note (pm)
   (if (< acur amin)(progn
    (setq amin acur)
    (setq pm p2)
   ))_if _progn
  ))_if _progn
 (setq n (+ 1 n))
 );_repeat
 (setq pm pm);returns pm
);_nextpoint
;;;;;;;;;;;;;;;;;;PRINTS THE LIST AS A LINE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun printlist(); / n p1)

;70.8 for 3d pline 66.1 for verticies follow
;70.32 ---- use 42.0 instead for pline

;sets 3dpolyline
;sets first point
;repeats the other poionts
;end polyline
(setq n 0)
(entmake      (list   (cons 0 "POLYLINE")  (cons 66 1) (cons 70   ))
(setq p1 (nth n list_pt))
(entmake (list (cons 0 "VERTEX")(cons 10 p1)(cons 70 32)))
(repeat length
(setq p1 (nth (setq n (+ 1 n)) list_pt))
(entmake (list (cons 0 "VERTEX")(cons 10 p1)(cons 70 32)))
);_repeat
(entmake (list (cons 0 "SEQEND")))
(princ)


);_printlist
;;;;;;;;;START MAIN PROGRAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;load in the geometry calculator
 (if (not c:cal)(arxload "geomcal"))
;sets world ucs
(command "ucs" "w")


;read in all point
(setq points (ssget '((0 . "POINT"))))
(setq length (sslength points))
;calculate centroif of points
(setq centroid (centroid points))
;calculate normal vector to points 
(setq p (norm points)) ;(only uses 3 points and assumes all are in a plane)
;create a list to store points in order and sets first point
(setq list_pt (list        (setq previousp (cdr (assoc 10 (entget (ssname points 0)))))    ))
;each time through (once for every point after first) add one coord to end of list_pt
(setq i 1)
(while (< i length)

 (setq list_pt (append list_pt (list (setq previousp (nextpoint)))))
 (setq i (+ 1 i))
);_while

;add first point to end of list to close area
(setq list_pt (append list_pt (list (nth 0 list_pt)) ))


(printlist)
;(plines)
);_defun




Link to comment
Share on other sites

Anyone know offhand how I would modify my program to automatically close the polyline I create?

 

Also, where could I find a reference for all entity codes?

 

Cheers!

Mark Camball

Link to comment
Share on other sites

http://images.autodesk.com/adsk/files/acad_dxf2.pdf

 

70 Polyline flag (bit-coded; default = 0):

1 = This is a closed polyline (or a polygon mesh closed in the M direction)

2 = Curve-fit vertices have been added

4 = Spline-fit vertices have been added

8 = This is a 3D polyline

16 = This is a 3D polygon mesh

32 = The polygon mesh is closed in the N direction

64 = The polyline is a polyface mesh

128 = The linetype pattern is generated continuously around the vertices of this polyline

Link to comment
Share on other sites

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...