|
发表于 2022-7-6 09:43:53
|
显示全部楼层
Hi SwChilly,
I'm a student also - welcome to the club
Now, onto your question - there are many ways to accomplish your task, some easier than others.
By far the simplest way would be to use the in-built PLine command and let AutoCAD do the work for you:
Method 1: Using the Pline command
- (defun c:test ( ) (command "_.pline") (while (= 1 (logand 1 (getvar 'CMDACTIVE))) (command pause)) (princ))
Here, I first call the PLine command using an underscore (_) so that the correct command is called on non-english versions of AutoCAD, and using a dot (.) to ensure the core PLine command is used, since a command can be redefined by the user.
The CMDACTIVE System Variable is a bit-coded value that determines whether a command, script, or LISP program etc is active. Hence, in the above program, the test condition for the While Loop checks whether the PLine command is still active, and, if so, pauses for user input.
Constructing a List of Points
Another way to gather your points would be to use the getpoint function and construct a list of points to use when creating your LWPolyline.
Again, there are many ways to go about this, here is one example:
- (if (setq p1 (getpoint "\nSpecify First Point: ")) (progn (setq lst (cons p1 lst)) (while (setq p2 (getpoint "\nSpecify Next Point: " p1)) (setq lst (cons p2 lst) p1 p2 ) ) (setq lst (reverse lst)) ))
I use cons since it is much faster than the append function, then reverse the final list so that the points are in order.
Notice that this construct could be condensed - consider the following:
- (if (car (setq lst (list (getpoint "\nSpecify First Point: ")))) (progn (while (car (setq lst (cons (getpoint "\nSpecify Next Point: " (car lst)) lst)))) (setq lst (reverse (cdr lst))) ))
Although, this isn't as readable as the previous example.
Now that we have a list of points, there are many routes we can follow to construct the LWPolyline:
Method 2: Using the PLine command with a List of Points
We could again use the PLine command to create the polyline:
- (defun c:test ( / p1 p2 lst ) (if (setq p1 (getpoint "\nSpecify First Point: ")) (progn (setq lst (cons p1 lst)) (while (setq p2 (getpoint "\nSpecify Next Point: " p1)) (setq lst (cons p2 lst) p1 p2 ) ) (command "_.pline") (foreach pt (reverse lst) (command "_non" pt) ) (command) ) ) (princ))
A few things to notice with the above code:
- I have localised the variables at the top of the code - this ensures the variables do not conflict with other variables using the same names. To see why this is important, read this tutorial.
- I have used "_non" before submitting each point to the PLine command - this ignores any Object Snap which may be set and which may affect the point supplied to the PLine command.
Method 3: Using entmake with a List of Points:
Now we are moving onto the more advanced methods of creating the LWPolyline, involving a little more work on our part since we are now modifying the drawing database directly.
I won't explain the ins and outs of the DXF code structure, but a reference for 2011 can be found here, describing the purpose for each of the codes.
Consider the following code example:
- (defun c:test ( / p1 p2 lst ) (if (setq p1 (getpoint "\nSpecify First Point: ")) (progn (setq lst (cons [color=red](cons 10 p1)[/color] lst)) (while (setq p2 (getpoint "\nSpecify Next Point: " p1)) (setq lst (cons [color=red](cons 10 p2)[/color] lst) p1 p2 ) ) (entmake (append (list (cons 0 "LWPOLYLINE") (cons 100 "AcDbEntity") (cons 100 "AcDbPolyline") (cons 90 (length lst)) (cons 70 0) ) (reverse lst) ) ) ) ) (princ))
Notice the highlighted changes to the method by which we collect the points - this is because the DXF code for a vertex of the LWPolyline is 10, and so we can construct each vertex entry as the list is constructed to save iterating through the whole list again later on.
[ Advanced: Accounting for UCS ]
Now, the above code will work correctly when the user is picking points in WCS, but, should the user be working in a UCS which differs from the WCS, we have to translate the points from the UCS to the WCS.
This can be accomplished using the trans function. Since the vertices of the LWPolyline are defined relative to the OCS of the LWPolyline, the UCS points need to be translated relative to the plane in which the LWPolyline will reside:
- (defun c:test ( / p1 p2 lst ucsz ) (setq ucsz (trans '(0. 0. 1.) 1 0 t)) ;; The Normal of the UCS Plane relative to WCS (if (setq p1 (getpoint "\nSpecify First Point: ")) (progn (setq lst (cons (cons 10 (trans p1 1 ucsz)) lst)) (while (setq p2 (getpoint "\nSpecify Next Point: " p1)) (setq lst (cons (cons 10 (trans p2 1 ucsz)) lst) p1 p2 ) ) (entmake (append (list (cons 0 "LWPOLYLINE") (cons 100 "AcDbEntity") (cons 100 "AcDbPolyline") (cons 90 (length lst)) (cons 70 0) (cons 210 ucsz) ) (reverse lst) ) ) ) ) (princ))
The above code will now work in all UCS/Views.
Method 3: Using Visual LISP
The LWPolyline can also be created using Visual LISP methods acting on the current space.
Consider the following code:
- (defun c:test ( / acdoc acspc p1 p2 lst ) (vl-load-com) (setq acdoc (vla-get-activedocument (vlax-get-acad-object)) acspc (vlax-get-property acdoc (if (= 1 (getvar 'CVPORT)) 'Paperspace 'Modelspace)) ) (if (setq p1 (getpoint "\nSpecify First Point: ")) (progn (setq lst (cons (cadr p1) (cons (car p1) lst))) (while (setq p2 (getpoint "\nSpecify Next Point: " p1)) (setq lst (cons (cadr p2) (cons (car p2) lst)) p1 p2 ) ) (vla-addlightweightpolyline acspc (vlax-make-variant (vlax-safearray-fill (vlax-make-safearray vlax-vbdouble (cons 0 (1- (length lst)))) (reverse lst) ) ) ) ) ) (princ))
The above code uses the AddLightWeightPolylinemethod on the active space (Modelspace or Paperspace) to create an LWPolyline. This method is slightly more complex since it uses Safearrays and Variants, and the point list is constructed slightly differently as the safearray requires a list of doubles as opposed to a list of points.
Interestingly, we can avoid the use of Safearrays and Variants by using the undocumented vlax-invoke function on the space object:
- (defun c:test ( / acdoc acspc p1 p2 lst ) (vl-load-com) (setq acdoc (vla-get-activedocument (vlax-get-acad-object)) acspc (vlax-get-property acdoc (if (= 1 (getvar 'CVPORT)) 'Paperspace 'Modelspace)) ) (if (setq p1 (getpoint "\nSpecify First Point: ")) (progn (setq lst (cons (cadr p1) (cons (car p1) lst))) (while (setq p2 (getpoint "\nSpecify Next Point: " p1)) (setq lst (cons (cadr p2) (cons (car p2) lst)) p1 p2 ) ) (vlax-invoke acspc 'addlightweightpolyline (reverse lst)) ) ) (princ))
Again, with the above Visual LISP code, the programs will only be correct for users working in WCS. The same coordinate transformations must be made to account for changes in the UCS.
Well, this post got a lot longer than I thought it would, so I hope I haven't bored you up to this point.
I realise some of the concepts introduced here are perhaps not for a beginner, but hopefully this post can benefit many users in the community, and users can read those sections they wish to learn.
If you have any questions about the content of this post, just ask and I would be happy to explain further.
Regards,
Lee |
|