Lisp to begin drawing line at the 'point' object

Lisp to begin drawing line at the 'point' object

Anonymous
Not applicable
5,251 Views
15 Replies
Message 1 of 16

Lisp to begin drawing line at the 'point' object

Anonymous
Not applicable

Hello everyone,

Have done a tonne of Googling on this one but all the results involve the wrong type of "points." I'm talking about the actual AutoCad object...the one whose style you can change & that appears when you use the divide command on a line etc.

I am chasing a segment of code to include in an action macro that will draw a number of multilines, extending/beginning from each point symbol on a line.

The action macro divides a selected line into 3 or 4 sections & places the point symbols but then I need to manually draw a line (multiline actually) that begins at each of those points. The lines are drawn to some arbitrary length & then the macro kicks in again to trim/extend them to the right length.

It would be nice to do this task with zero user input required but I can't find a way of initiating a line from the 'point' entity.

Thanks everyone who bothers to read this.

0 Likes
Accepted solutions (1)
5,252 Views
15 Replies
Replies (15)
Message 2 of 16

chriscowgill7373
Advisor
Advisor

I'm not sure on the exact coding, it seems like it would be quite complicated, but you would need to take the points that were added, and get them into a selection set to run through, and then issue the multi line command to run from each of those points.

The running through isnt an issue, this can be a foreach, or even a while loop.  I'm not sure how you created your measured points, but if you did it manually (not using a measure command) you should be able to store those points in a list as they are created, for cycling through after the face.

The coordinate of each point would be the start point for your line. if you have it done right, you may be able to figure out how to get it to draw perpendicular to the line at that point the specified distance you want, instead of trimming anything.


Christopher T. Cowgill, P.E.

AutoCAD Certified Professional
Civil 3D Certified Professional
Civil 3D 2024 on Windows 10

Please select the Accept as Solution button if my post solves your issue or answers your question.

0 Likes
Message 3 of 16

ВeekeeCZ
Consultant
Consultant

Not sure if anyone here has some real (and good) experience with a macro recorder. 

 

If you post some sample drawing with states before and after to clearly see what your goal is, we could try to figure out some suitable algorithm.

0 Likes
Message 4 of 16

dlanorh
Advisor
Advisor
Accepted solution

You would probably need a bespoke divide command that would collect the points (nodes) inserted. This would allow a multiline to be started from each point. Otherwise you will have to collect the points after the normal divide command runs into a selection set and process from there. If the mlines are to run perpendicular to the line at the node, this could also be automated, although you would need to supply a distance for the mline. This distance could also be used to determine if the mline is to the left of the original lines direction or the right by entering a positive or negative number.

 

Try this

 

(defun c:test (/ c_doc c_spc ss segs dist cnt ent len s_len p_len pt1 ang pt2)
  (setq c_doc (vla-get-activedocument (vlax-get-acad-object))
        c_spc (vlax-get-property c_doc (if (= 1 (getvar 'cvport)) 'paperspace 'modelspace))
        ss (ssget '((0 . "LINE,POLYLINE,LWPOLYLINE,ARC")))
        segs (getint "\nNumber of segments per object : ")
        dist (getreal "\nMline Distance : ")
  )
  (repeat (setq cnt (sslength ss))
    (setq ent (ssname ss (setq cnt (1- cnt)))
          len (vlax-curve-getdistatparam ent (vlax-curve-getendparam ent))
          s_len (/ len segs)
          p_len s_len
    )
    (while (< p_len len)
      (setq pt1 (vlax-curve-getpointatdist ent p_len)
            ang (angle '(0. 0. 0.) (vlax-curve-getfirstderiv ent (vlax-curve-getparamatpoint ent pt1)))
            pt2 (if (minusp dist) (polar pt1 (- ang (* pi 0.5)) (abs dist)) (polar pt1 (+ ang (* pi 0.5)) (abs dist)))
      )
      (vlax-invoke c_spc 'addmline (apply 'append (list pt1 pt2)))
      (setq p_len (+ p_len s_len))
    )
  )
  (princ)
)

 

I am not one of the robots you're looking for

0 Likes
Message 5 of 16

gccdaemon
Collaborator
Collaborator

This should get you started. it limits the osnap to a node (point).

 

;; GETNOD			Get node snap Form: (GETNOD <prompt1> <error prompt>)
;;Example: (setq PTSW (GETNOD nil "\nPick LOWER LEFT point on the detail border: " "\nNo point selected: "))

(defun GETNOD (P MSG1 MSG2 / PNT) (while (and (setq PNT (if P (getpoint P MSG1) (getpoint MSG1))) (not (setq PNT (osnap PNT "_nod"))) (princ MSG2) ) ) PNT )
Andrew Ingram
Civil 3D x64 2019
Win 10 x64 Pro
Intel Xeon E5-1620
32 GB Ram
0 Likes
Message 6 of 16

Kent1Cooper
Consultant
Consultant

If you're using DIVIDE only to get Points placed in order to use the Points as origins for something else, you don't need them as temporary markers.  You can use DivideMeasurePlus.lsp with its DIV+ command, available >here<.  One of its many enhancements over regular DIVIDE is that you have the option to put a User selection  [in your case one of your MLINEs, but it can even be multiple objects] at the dividing points, not just Points or Blocks [and you can also opt for Lines  of User-specified length centered on and perpendicular to the path object].  See the comments at the link, and in the file, and follow the prompts.

Kent Cooper, AIA
0 Likes
Message 7 of 16

Anonymous
Not applicable

Hey dlanorh,

 

Thank you so very much for this.  Works a treat and has slotted into my action macro perfectly.   Really appreciate your sharing your hard work with me.

0 Likes
Message 8 of 16

Anonymous
Not applicable

Hi Kent,

 

I can see how the DivideMeasurePlus.lsp has great potential, for some strange reason though, every time I ran it, it turned off/reset all my snapping settings and I would have to go into the options to re-tick all the snap options I wanted to use in my drawings again.  Another user here replied with some code that did the trick.

 

Thank you to everyone who replied, its a great community here.

 

Brad

0 Likes
Message 9 of 16

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

…. DivideMeasurePlus.lsp has great potential, for some strange reason though, every time I ran it, it turned off/reset all my snapping settings ….

 


Looking it over, I see that it was written before a change in the use of (command) functions in *error* handling [it's a long story].  I imagine there was a message about it when your Osnap setting wasn't restored.  Try changing this line:

 

  (command "_.undo" "_end")

 

to this:

 

  (command-s "_.undo" "_end")

Kent Cooper, AIA
0 Likes
Message 10 of 16

dlanorh
Advisor
Advisor

Not a problem. It was just a concept. If you need it expanding, like placing the mlines on a certain layer, let me know.

I am not one of the robots you're looking for

0 Likes
Message 11 of 16

Anonymous
Not applicable

"Not a problem. It was just a concept. If you need it expanding, like placing the mlines on a certain layer, let me know."

 

Hello again and thank you for the kind offer to add to what you have already given me.  Please let me try to explain my worflow here:

I currently use your code in a recorded action macro that divides the selected bottom line by 3 or 4 sections and extends 2 or 3 of my custom multilines from those divide points.  The action then activates the 'extend' command where I select the line above and extend the newly created multilines to that selected line.  Hopefully a combination of my explanation oand the atached image makes this clear.

Whilst this process is working, I wonder how much effort and/or time on your part it would take to modify your code to:

a.) Bypass the option for selecting number of divide points and automatically just select 3 (I could change it to 4 where required) and extend my multilines from those points.

b.) Then skip straight to selecting a line to extend the multilines to (that distance is always different so the created lines cant be given a constant/static length).

This would essentially remove the need for me to run an action macro and make the whole process easier/quicker.  This is a task I need to perform 4-5 times per drawing at 15-20 drawings per day.

 

I am terribly new to AutoLisp so if what I have asked is too much or would take too much of your time, please just let me know; you have already been very good to me.

 

Hope to hear from you (or anyone for that matter).

0 Likes
Message 12 of 16

Anonymous
Not applicable

Thanks again Kent.  Do I need to replace those snippets of code every time they appear in the original or just in the first instance?  I think that line appears 4-5 times in the original.

 

Cheers matey

0 Likes
Message 13 of 16

dlanorh
Advisor
Advisor

Are the top and bottom lines always parallel?

I am not one of the robots you're looking for

0 Likes
Message 14 of 16

Anonymous
Not applicable

Yeah always parallel.

0 Likes
Message 15 of 16

dlanorh
Advisor
Advisor

Try the attached. I have removed the mline distance prompt. You are asked to select the "Extend From" line, then the "Extend To" line. The next prompt is for the number of segments (default 3 so 2 mlines). At this prompt you can select the default (3) by pressing enter or right clicking with the mouse, or entering a new integer number. The lisp automatically finds the distance from the start point to the "Extend To" line and inserts the appropriate length mline.

Finally you are asked if you want to "Repeat [Yes/No] <Yes>". The lisp is looping here and makes use of dynamic mode and the dynamic prompt, so you can select Yes or No with the mouse on screen. The default here is Yes and as above can be selected by right clicking with the mouse. This will loop back to repeat the process. Selecting No will exit the lisp.

 

(vl-load-com)

(defun c:test (/ *error* c_doc c_spc sv_lst sv_vals flg b_ent t_ent segs len s_len p_len t_obj pt1 ang x_obj i_pt)

  (defun *error* (msg)
    (mapcar 'setvar sv_lst sv_vals)
    (if (not (wcmatch (strcase msg) "*BREAK*,*CANCEL*,*EXIT*")) (princ (strcat "\nOops an Error : ( " msg " ) occurred.")))
    (princ)
  );end_error_on_defun

  (setq c_doc (vla-get-activedocument (vlax-get-acad-object))
        c_spc (vlax-get-property c_doc (if (= 1 (getvar 'cvport)) 'paperspace 'modelspace))
        sv_lst (list 'cmdecho 'osmode 'dynmode 'dynprompt)
        sv_vals (mapcar 'getvar sv_lst)
  );end_setq

  (mapcar 'setvar sv_lst (list 0 0 3 1))
  
  (while (not flg)
    (while (not b_ent)
      (setq b_ent (car (entsel "\nSelect Extend From Line : ")))
      (cond ( (not (vl-position (cdr (assoc 0 (entget b_ent))) (list "LINE" "POLYLINE" "LWPOLYLINE")))
              (alert "NOT a Line or Polyline")
              (setq b_ent nil)
            )
      );end_cond
    );end_while

    (while (not t_ent)
      (setq t_ent (car (entsel "\nSelect Extend To Line : ")))
      (cond ( (not (vl-position (cdr (assoc 0 (entget t_ent))) (list "LINE" "POLYLINE" "LWPOLYLINE")))
              (alert "NOT a Line or Polyline")
              (setq t_ent nil)
            )
      );end_cond
    );end_while

    (initget 6)
    (setq segs (cond ( (getint "\nNumber of segments per object : <3>")) (3)))

    (setq len (vlax-curve-getdistatparam b_ent (vlax-curve-getendparam b_ent))
          s_len (/ len segs)
          p_len s_len
          t_obj (vlax-ename->vla-object t_ent)
    );end_setq

    (while (< p_len len)
      (setq pt1 (vlax-curve-getpointatdist b_ent p_len)
            ang (angle '(0. 0. 0.) (vlax-curve-getfirstderiv b_ent (vlax-curve-getparamatpoint b_ent pt1)))
            x_obj (vlax-invoke c_spc 'addxline pt1 (polar pt1 (+ ang (* pi 0.5)) 1.0))
            i_pt (vlax-invoke x_obj 'intersectwith t_obj acextendnone)
      );end_setq

      (vla-delete x_obj)
      (vlax-invoke c_spc 'addmline (apply 'append (list pt1 i_pt)))
      (setq p_len (+ p_len s_len))
    )

    (initget "Yes No")
    (if (= (cond ( (getkword "\nRepeat ? [Yes/No] <Yes> ")) ("Yes")) "No") (setq flg T))
  );end_main_while

  (mapcar 'setvar sv_lst sv_vals)
  (princ)
);end_defun

 

I am not one of the robots you're looking for

0 Likes
Message 16 of 16

Kent1Cooper
Consultant
Consultant

@Anonymous wrote:

....  Do I need to replace those snippets of code every time they appear in the original or just in the first instance?  ….


 

Only the first one, which is in the shared error handler.  It's only within error handling that (command) functions should be (command-s) instead [or handled by other more complicated shenanigans].

Kent Cooper, AIA
0 Likes