Jump to content

Recommended Posts

Posted

Hi,

Have a small problem.

I'm trying to write a Lisp code where the user first draws a polyline and the function returns its coordinates instantly.

The problem is that my function returns the coord. of the polyline that was drawn before the recently drawn polyline. Does the AutoCAD refer to the last entity it has in its memory prior to activating the function ? what should I do ?

 

here's my little code :

 

(defun get_coords()

 

(vl-load-com)

;draw a polyline, reteieve it and convert it to a vla object

(setq userPolyline (vlax-ename->vla-object (entlast)))

 

(setq userPolyVertices (vlax-get-property userPolyline 'coordinates))

;convert the userPolyVertices (#variants) to a list:

(setq userPolyVertices (vlax-safearray->list (variant-value userPolyVertices))))

 

); defun

Posted

Here is an example for you to consider:

 

(defun c:test ( / ent )
[color=green]    ;; Retrieve last entity added to drawing database (may be nil)[/color]
   (setq ent (entlast))
[color=green]    ;; Start PLINE command[/color]
   (command "_.pline")
[color=green]    ;; While the PLINE command is active, pause for user input[/color]
   (while (= 1 (logand 1 (getvar 'cmdactive)))
       (command "\\")
   )
[color=green]    ;; Retrieve the last entity added to the drawing database
   ;; and check that it doesn't equal the value of entlast before
   ;; the PLINE command was used.[/color]
   (if (not (eq ent (setq ent (entlast))))
[color=green]        ;; For every DXF Group in the DXF data for the entity[/color]
       (foreach dxf (entget ent)
[color=green]            ;; If the pair is a Group 10 code[/color]
           (if (= 10 (car dxf))
[color=green]                ;; Print the vertex coordinate[/color]
               (print (cdr dxf))
           )
       )
   )
[color=green]    ;; Suppress the return of the last expression[/color]
   (princ)
)

PS: Formatting code in your posts.

Posted

Consider this example:

 

(vl-load-com)

(defun _GetPlineCoords (oPline)
 (vlax-get oPline 'coordinates)
)

(defun c:FOO (/ ss)
 (if (setq ss (ssget ":S:E" '((0 . "*POLYLINE"))))
   (princ
     (_GetPlineCoords (vlax-ename->vla-object (ssname ss 0)))
   )
   (prompt "\n** Nothing selected, or invalid object ** ")
 )
 (princ)
)

... As to how to get the last entity, be sure you store the last entity prior to creating the one you wish to query.

 

HTH

Posted

The code works perfectly now. Thanks a lot !

Posted

Thanks,

Can you help me a bit more ? instead of just printing the coordinates, I want to store them in an array to use to this array later.

Posted

You can construct a list of coordinates using the cons function, for example:

 

Replace:

(print (cdr dxf))

With:

(setq lst (cons (cdr dxf) lst))

Be aware that by its construction, the list will be reversed, so a call to the reverse function may be required.

Posted
Thanks,

Can you help me a bit more ? instead of just printing the coordinates, I want to store them in an array to use to this array later.

It's usually a lot simpler to use lists in lisp. The safearray is a bit complex.

 

To generate lists use the cons function to add a value to the front of a list. E.g. using Lee's code:

(defun c:test ( / ent )
   ;; Retrieve last entity added to drawing database (may be nil)
   (setq ent (entlast))
   ;; Start PLINE command
   (command "_.pline")
   ;; While the PLINE command is active, pause for user input
   (while (= 1 (logand 1 (getvar 'cmdactive)))
       (command "\\")
   )
   ;; Retrieve the last entity added to the drawing database
   ;; and check that it doesn't equal the value of entlast before
   ;; the PLINE command was used.
   (if (not (eq ent (setq ent (entlast))))
       (progn
         ;; Initialize the *MyCoodinates* global variable to an empty list
           (setq *MyCoodinates* nil)
           ;; For every DXF Group in the DXF data for the entity
           (foreach dxf (entget ent)
               ;; If the pair is a Group 10 code
               (if (= 10 (car dxf))
                   (progn
                       ;; Print the vertex coordinate
                       (print (cdr dxf))
                       ;; Save point to the front of *MyCoodinates*
                       (setq *MyCoodinates* (cons (cdr dxf) *MyCoodinates*))
                   )
               )
           )
           ;; Reverse *MyCoodinates* since you created it by adding to its front
           (setq *MyCoodinates* (reverse *MyCoodinates*))
       )
   )
   ;; Suppress the return of the last expression
   (princ)
)

After you've run this command the variable *MyCoodinates* contains a list. Each item of which is a sublist containing the XYZ values of the point. So you can use the foreach to step through all of them, or nth to get a single point from a specified index. Or any of the other list functions like, append, mapcar, car, cdr, etc.

Posted

Thanks. Why did you use a global variable? Suppose you define 'MyCoordinates' without the '*',

would your receive and empty list at the end ? Do the parentheses impose scoping restrictions on variables ?

Posted

The scoping of variables is determined by their being (or not being) specified as an argument, or [localized] variable within the Defun statement. A variable that is defined, and is not specified as a [localized] variable is considered to be a 'global' variable.

 

Example:

(defun [i]sym ([arguments] [/ <localVariables>][/i]) expr...) 

 

It is fairly common for special characters, such as "*" and the like to be used to distinguish a 'global' variable from those which are specified as 'local'. Adding these characters in no way changes the ability to store data.

 

HTH

Posted
Thanks. Why did you use a global variable? Suppose you define 'MyCoordinates' without the '*',

would your receive and empty list at the end ? Do the parentheses impose scoping restrictions on variables ?

I defined it as global because this is a command. Notice the (princ) at the end and the c: prefix. If you want it to return the list to some other defun, then you'd have to design it as a callable function instead - in which case the list can be a localized variable (and probably should be). As long as it's the last expression to run in the defun, its value is returned as the result. But seeing as I've used your sample command as a basis, the idea would be to obtain the list into a global variable. Then you can use that from any other function / command as input data.

 

RM's correct about the scoping. The * does not make it a global, it's just a convention to signify that it's meant to be global. Helps to not screw up other stuff, since global variables can be dangerous things.

 

A much better method (IMO) would be to define a helper function extracting the vector points from the polyline's dxf data (or you could extract it from the ActiveX data is you prefer):

(defun GetPLVectors  (obj /)
 (cond ((or (listp obj) (and (= (type obj) 'EName) (setq obj (entget obj))))
        (mapcar 'cdr (vl-remove-if-not '(lambda (data) (= (car data) 10)) obj)))
       ((= (type obj) 'VLA-Object) (list-gbn (vlax-get obj 'Coordinates) 2))))

Notice I'm not using any extra variables (global or otherwise). Though I'm using a helper function for the VLA case - from this thread: http://www.theswamp.org/index.php?topic=41419.15

 

That way you can use it inside any other defun (even commands) to extract only the vector points from a polyline (when and if needed).

 

Also note, I'm using other ways of creating the list of points:

 

From the DXF data it first removes every DXF item with it's code (vl-remove-if-not + lambda + car) not equal to 10. Then it strips the car from those which are left (mapcar + cdr).

From a vla-object's Coordinates property I group the list of numbers by 2 (since the array is single dimensional and uses 2D points).

Posted
Thanks,

Can you help me a bit more ? instead of just printing the coordinates, I want to store them in an array to use to this array later.

 

Could you help me a bit more and edit your first post to use CODE TAGS?

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