move selected/named block(s) to nearest *line vertex

move selected/named block(s) to nearest *line vertex

jtm2020hyo
Collaborator Collaborator
3,087 Views
13 Replies
Message 1 of 14

move selected/named block(s) to nearest *line vertex

jtm2020hyo
Collaborator
Collaborator

I request to create a lisp to move selected blocks (dynamic, regular, nested) to the nearest vertex of polyline, line,  arc, spline, etc (any object that has editable vertex).

 

imagen.png

0 Likes
Accepted solutions (2)
3,088 Views
13 Replies
Replies (13)
Message 2 of 14

Anonymous
Not applicable

You are not bothering or researching if your question has already been answered, before you post it is always good to do a search first.

Message 3 of 14

dlanorh
Advisor
Advisor
Accepted solution

Try this

 

(vl-load-com)

(defun c:BTV ( / *error* c_doc sv_lst sv_vals ss ent cnt obj i_pt c_pt c_p v_pt)

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

  (setq c_doc (vla-get-activedocument (vlax-get-acad-object))
        sv_lst (list 'cmdecho 'osmode)
        sv_vals (mapcar 'getvar sv_lst)
  );end_setq

  (mapcar 'setvar sv_lst '(0 0))

  (prompt "\nSelect Blocks : ")
  (setq ss (ssget "_:L" '((0 . "INSERT"))))

  (cond (ss
          (setq ent (car (entsel "Select Alignment Line : ")))
          (repeat (setq cnt (sslength ss))
            (setq obj (vlax-ename->vla-object (ssname ss (setq cnt (1- cnt))))
                  i_pt (vlax-get obj 'insertionpoint)
                  c_pt (vlax-curve-getclosestpointto ent i_pt)
                  c_p (vlax-curve-getparamatpoint ent c_pt)
            )
            (if (> (rem c_p 1.0) 0.49) (setq v_pt (vlax-curve-getpointatparam ent (1+ (fix c_p)))) (setq v_pt (vlax-curve-getpointatparam ent (fix c_p))))
            (vlax-put obj 'insertionpoint v_pt)
          );end_repeat
        );end_sub_cond
  );end_cond

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

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

Message 4 of 14

jtm2020hyo
Collaborator
Collaborator

@Anonymous wrote:

You are not bothering or researching if your question has already been answered, before you post it is always good to do a search first.


 

✔️✔️

0 Likes
Message 5 of 14

jtm2020hyo
Collaborator
Collaborator

can you add one lastest "press enter" in the end?

I need to select multiple *lines

0 Likes
Message 6 of 14

Kent1Cooper
Consultant
Consultant

So many questions arise....

 

What constitutes an "editable vertex" on various entity types?  It's obvious enough for a Polyline, since they have what are explicitly called  vertices, which are stored in entity data, and have grips at them.  But the midpoints of segments also have grips -- do you want those considered?  For a Line, do you want only locations defined/stored in entity data  [which would mean only its endpoints], or all Osnappable or grip-marked locations [which would add the midpoint]?  For an Arc, the endpoints and midpoint have grips at them, but none  of those are stored in entity data, so they need to be calculated.  For a Spline, if it's an original drawn by picking a few points, those few Fit points are stored in entity data and extractable easily enough, but if it's the result of certain operations such as Offsetting from another Spline, suddenly it has a heck of a lot more grip points and Control and Fit points in entity data -- how many of those would qualify as locations you want to move Blocks to?  Etc., etc.

 

@dlanorh 's suggestion looks like it would work if the nearest "path" object is a Polyline, but since it's based on rounding to whole parameter values, it will go to places you probably don't want on other entity types.  Whole-number parameter values on a Line or Spline are 1-drawing-unit increments along its length, on an Arc are one-radian increments along its direction from the center [which means its start parameter is usually not 0 as for many other entity types], on a Circle are the same but at least the start parameter is 0, etc.  Most whole-number parameter locations on other-than-Polyline entities will not  fall at "editable vertex" positions, however that is defined.

[Also, it requires you to pick that Polyline.  I had the impression from Message 1 that you would want the routine to find  the nearest available "path" object.  Can you clarify?]

Kent Cooper, AIA
Message 7 of 14

dlanorh
Advisor
Advisor

You want this to repeat, or you want to choose multiple lines? The first is easy, the second extremely complicated.

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

Message 8 of 14

jtm2020hyo
Collaborator
Collaborator

I want to select multiple lines. but if complicated, then might you modify the lisp to move the selected blocks to any vertex between the show objects or entire drawing, but just the editable vertex?

 

editable vertex: any vertex that can be modified and can be selected with left click, for example, line and polylines

uneditable vertex: any vertex that can not be modified, for example, lines and polylines inside blocks

0 Likes
Message 9 of 14

jtm2020hyo
Collaborator
Collaborator

@Kent1Cooper wrote:

So many questions arise....

 

What constitutes an "editable vertex" on various entity types?  It's obvious enough for a Polyline, since they have what are explicitly called  vertices, which are stored in entity data, and have grips at them.  But the midpoints of segments also have grips -- do you want those considered?  For a Line, do you want only locations defined/stored in entity data  [which would mean only its endpoints], or all Osnappable or grip-marked locations [which would add the midpoint]?  For an Arc, the endpoints and midpoint have grips at them, but none  of those are stored in entity data, so they need to be calculated.  For a Spline, if it's an original drawn by picking a few points, those few Fit points are stored in entity data and extractable easily enough, but if it's the result of certain operations such as Offsetting from another Spline, suddenly it has a heck of a lot more grip points and Control and Fit points in entity data -- how many of those would qualify as locations you want to move Blocks to?  Etc., etc.

 

@dlanorh 's suggestion looks like it would work if the nearest "path" object is a Polyline, but since it's based on rounding to whole parameter values, it will go to places you probably don't want on other entity types.  Whole-number parameter values on a Line or Spline are 1-drawing-unit increments along its length, on an Arc are one-radian increments along its direction from the center [which means its start parameter is usually not 0 as for many other entity types], on a Circle are the same but at least the start parameter is 0, etc.  Most whole-number parameter locations on other-than-Polyline entities will not  fall at "editable vertex" positions, however that is defined.

[Also, it requires you to pick that Polyline.  I had the impression from Message 1 that you would want the routine to find  the nearest available "path" object.  Can you clarify?]


here my notes:

1) I just want move to endpoints (I can them vertex for the polylines)

2) for me, "editable vertex": any vertex that can be modified and can be selected with left click, for example, line and  polylines

3) for me, "uneditable vertex": any vertex that can not be modified, for example, lines and polylines inside blocks

4) for every object (POLYLINE, LINE, ARC, LWPOLYLINE, SPLINE, ELLIPSE, 3DPOLYLINE)  with "editable vertex" (endpoints that can be selected with a left click) just should be considered their endpoints, but if possible add more options, for example, align block to midpoints, is welcome.

5) I need to select multiple blocks and select other multiple lines, if this is complicated, then just move the block to the nearest "editable vertex" (endpoints) in the entire drawing or showed objects.

6) thanks for your reply.

0 Likes
Message 10 of 14

dlanorh
Advisor
Advisor

@jtm2020hyo wrote:

I want to select multiple lines. but if complicated, then might you modify the lisp to move the selected blocks to any vertex between the show objects or entire drawing, but just the editable vertex?

 

editable vertex: any vertex that can be modified and can be selected with left click, for example, line and polylines

uneditable vertex: any vertex that can not be modified, for example, lines and polylines inside blocks


The highlighted (red) text above makes no sense. A better explanation is needed of what you are trying to achieve.

 

 

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

Message 11 of 14

jtm2020hyo
Collaborator
Collaborator

If not possible select multiple objects with vertex endpoints (POLYLINE, LINE, ARC, LWPOLYLINE, SPLINE, ELLIPSE, 3DPOLYLINE, MULTILINE) then simply the block should move to the nearest endpoint in the entire drawing.

 

I mean:

 

user type BTV (your write lisp)

lisp request for select blocks to move

lisp request press enter (select lines were deleted, and block should move to any object with endpoints)

 

I just want BEDIT, then use the lisp to move the blocks inside the BEDIT window to the nearest endpoints.

 

selecting or not selecting is optional, I just optional, I just want to move all blocks to multiple lines endpoints.

 

0 Likes
Message 12 of 14

dlanorh
Advisor
Advisor
Accepted solution

@jtm2020hyo wrote:

If not possible select multiple objects with vertex endpoints (POLYLINE, LINE, ARC, LWPOLYLINE, SPLINE, ELLIPSE, 3DPOLYLINE, MULTILINE) then simply the block should move to the nearest endpoint in the entire drawing.

 

I mean:

 

user type BTV (your write lisp)

lisp request for select blocks to move

lisp request press enter (select lines were deleted, and block should move to any object with endpoints)

 

I just want BEDIT, then use the lisp to move the blocks inside the BEDIT window to the nearest endpoints.

 

selecting or not selecting is optional, I just optional, I just want to move all blocks to multiple lines endpoints.

 


Below is an updated lisp that accounts for ellipses,arcs,lines and splines. It isn't possible possible to account for mlines as these don't work with the vlax-curve functions (from my tests) or xlines (infinite length so no start or end points). I have therefore excluded them. Rays only have a start point so I haven't included them either.

 

I still don't completely understand what you require. This should work in model/paper space or in the block editor (briefly tested). If in the block editor, only nested blocks and block "lines" are selectable. Nothing in model/paperspace is affected. The problem will arise if you want to align blocks model/paperspace to lines inside blocks. This isn't possible as the line isn't seen as a line but a block.

 

The current lisp is automated using the "_A" Selection mode string (all blocks visible blocks not on locked layers)

If you want to specify which blocks and lines then change the "_A" to "_:L" in both ssget's.

 

(defun rh:ss2lst ( ss opt / cnt lst)
  (cond ( (and ss (= (type ss) 'PICKSET)) 
          (repeat (setq cnt (sslength ss)) (setq lst (cons (ssname ss (setq cnt (1- cnt))) lst)))
          (if opt (setq lst (mapcar 'vlax-ename->vla-object lst)))
        )
  );end_cond
  lst
);end_defun

(defun c:BTV ( / *error* c_doc sv_lst sv_vals b_lst l_lst i_pt s_pt e_pt c_pt c_p e_p v_pt lst len)

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

  (setq c_doc (vla-get-activedocument (vlax-get-acad-object))
        sv_lst (list 'cmdecho 'osmode)
        sv_vals (mapcar 'getvar sv_lst)
  );end_setq

  (mapcar 'setvar sv_lst '(0 0))

  (setq b_lst (rh:ss2lst (ssget "_A" '((0 . "INSERT"))) t)
        l_lst (rh:ss2lst (ssget "_A" '((0 . "*LINE,ARC,ELLIPSE") (-4 . "<NOT") (0 . "XLINE,MLINE") (-4 . "NOT>"))) nil)
  );end_setq
  
  (cond ( (and (> (length b_lst) 0) (> (length l_lst) 0))
          (foreach b b_lst
            (foreach lent l_lst
              (setq i_pt (vlax-get b 'insertionpoint)
                    s_pt (vlax-curve-getstartpoint lent)
                    e_pt (vlax-curve-getendpoint lent)
                    c_pt (vlax-curve-getclosestpointto lent i_pt)
                    c_p (vlax-curve-getparamatpoint lent c_pt)
                    e_p (vlax-curve-getendparam lent)
              );end_setq
              (cond ( (= (fix e_p) e_p)
                      (if (> (rem c_p 1.0) 0.49)
                        (setq lst (cons (list (setq v_pt (vlax-curve-getpointatparam lent (1+ (fix c_p)))) (distance i_pt v_pt)) lst))
                        (setq lst (cons (list (setq v_pt (vlax-curve-getpointatparam lent (fix c_p))) (distance i_pt v_pt)) lst))
                      );end_if
                    )
                    (t
                      (setq len (vlax-curve-getdistatparam lent e_p))
                      (if (> (vlax-curve-getdistatpoint lent c_pt) (/ len 2.0))
                        (setq lst (cons (list e_pt (distance i_pt e_pt)) lst))
                        (setq lst (cons (list s_pt (distance i_pt s_pt)) lst))
                      );end_if
                    )
              );end_cond
            );end_foreach
            (setq lst (vl-sort lst '(lambda (x y) (< (cadr x) (cadr y)))))
            (vlax-put b 'insertionpoint (caar lst))
            (setq lst nil)
          );end_foreach
        );end_sub_cond
  );end_cond

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

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

Message 13 of 14

jtm2020hyo
Collaborator
Collaborator

pretty good. I like it.

 

...but can you add the option to select the blocks than I want to move again like the first lisp and keep the option to move the blocks selected to any nearest endpoint?

0 Likes
Message 14 of 14

krazeymike
Enthusiast
Enthusiast

I was wondering how I might tweak the "BTV" of this command so that the insertion points of my block snap to the mid point of the nearest line rather than the end points.
It would be also really nice to be able to have a selection set of blocks like the first version of the command without having to manually select each alignment.
It's just a bit beyond my lisp abilities tweaking the current code.

Thankyou in advance

 

Update

Found what I was looking for here
https://www.cadtutor.net/forum/topic/59757-mass-move-blocks-to-nearest-line/