Block align to end pline (s) multiples

Block align to end pline (s) multiples

Edwin.Saez
Advisor Advisor
4,256 Views
45 Replies
Message 1 of 46

Block align to end pline (s) multiples

Edwin.Saez
Advisor
Advisor

Hi

I come to your great help: oops: so I can Provide some lisp routine for the following:

* I want to place a block That multiply at the ends of Several polylines, perpendicular and Placing them to leave the color, and the layer of each polyline are Selecting.
I Explained in the best dwg I'm attached.

Edwin Saez


LinkedIn / AutoCAD Certified Professional


EESignature


 


Si mi respuesta fue una solución para usted, por favor seleccione "Aceptar Solución", para que también sirva a otro usuarios.

0 Likes
Accepted solutions (3)
4,257 Views
45 Replies
Replies (45)
Message 21 of 46

ВeekeeCZ
Consultant
Consultant

Ok, my try now 🙂 Just quicly.

It looks at both ends of line/polyline and if one is with free sourounding space and second is close to some other obejct, then takes a free one. If this does not apply, then used is asked to select desired end.

 

Spoiler
(vl-load-com)

(defun c:caps ( / en ss i sb se pb pe la pt ang)

  (if (and (or *cap-block*
	       (setq *cap-block* (if (and (setq en (car (entsel "\nSelect a cup block: ")))
					  (= "INSERT" (cdr (assoc 0 (entget en)))))
				   (cdr (assoc 2 (entget en))))))
	   (setq ss (ssget '((0 . "LWPOLYLINE,LINE"))))
	   (not (command "_.ZOOM" "_E"))
	   (sssetfirst nil nil)
	   )
    (repeat (setq i (sslength ss))
      (setq en (ssname ss (setq i (1- i)))
	    pb (vlax-curve-getStartPoint en)
	    pe (vlax-curve-getEndPoint en)
	    sb (ssget "_C" (polar pb (* pi 0.5) 2) (polar pb (* pi 1.5) 3))
	    se (ssget "_C" (polar pe (* pi 0.5) 2) (polar pe (* pi 1.5) 3))
	    la (cdr (assoc 8 (entget en))))
      (if (and (or (and (= 1 (sslength sb))
			(/= 1 (sslength se))
			(setq pt pb))
		   (and (/= 1 (sslength sb))
			(= 1 (sslength se))
			(setq pt pe))
		   (and (progn
			  (redraw en 3)
			  (vla-GetBoundingBox (vlax-ename->vla-object en) 'PtArMin 'PtArMax)
			  (command "_.ZOOM" "_W" (vlax-safearray->list PtArMin) (vlax-safearray->list PtArMax))
			  T)
			(setq pt (cadr (entsel "\nSelect ent closer to desired end: ")))
			(setq pt (osnap pt "end"))
			(not (command "_.ZOOM" "_E")))
		   )
	       (setq ang  (angle '(0 0 0) (vlax-curve-getFirstDeriv en (vlax-curve-getParamAtPoint en (vlax-curve-getClosestPointTo en pt)))))
	       )
	(command "_.INSERT" *cap-block* "_none" "_s" 5 pt (angtos ang)
		 "_.CHPROP" "_L" "" "_La" la ""))))
  (command "_.REGEN")
  (princ)
)

 

 

Message 22 of 46

Edwin.Saez
Advisor
Advisor

@ВeekeeCZ You are a teacher,

the code works perfect, Smiley Happy


if not much trouble could it be that so do not ask me which side to place the lid when it is free, it could be placed on both sides?
I also attached a picture so you can see in some cases the block is inserted with reverse rotation. Could you please fix that?

 

Thanks for your great help Man Very Happy

 

Block2.jpg

 

Edwin Saez


LinkedIn / AutoCAD Certified Professional


EESignature


 


Si mi respuesta fue una solución para usted, por favor seleccione "Aceptar Solución", para que también sirva a otro usuarios.

0 Likes
Message 23 of 46

ВeekeeCZ
Consultant
Consultant
Accepted solution

Sure... try and let know. I added undo and UCS support.

 

Spoiler
(vl-load-com)

(defun c:caps ( / *error* en ss i sb se pb pe la pt ang par)
  
  (defun *error* (errmsg)
    (if (not (wcmatch errmsg "Function cancelled,quit / exit abort,console break"))
      (princ (strcat "\nError: " errmsg))
      ); if
    (vla-endundomark doc)
    (princ)
    )
  
  (vla-startundomark (setq doc (vla-get-activedocument (vlax-get-acad-object))))
  
  (if (and (or *cap-block*
	       (setq *cap-block* (if (and (setq en (car (entsel "\nSelect a cup block: ")))
					  (= "INSERT" (cdr (assoc 0 (entget en)))))
				   (cdr (assoc 2 (entget en))))))
	   (setq ss (ssget '((0 . "LWPOLYLINE"))))
	   (not (command "_.ZOOM" "_E"))
	   (sssetfirst nil nil)
	   )
    (repeat (setq i (sslength ss))
      (setq en (ssname ss (setq i (1- i)))
	    pb (vlax-curve-getStartPoint en)
	    pe (vlax-curve-getEndPoint en)
	    sb (ssget "_C" (polar (trans pb 0 1) (* pi 0.5) 3) (polar (trans pb 0 1) (* pi 1.5) 3))
	    se (ssget "_C" (polar (trans pe 0 1) (* pi 0.5) 3) (polar (trans pe 0 1) (* pi 1.5) 3))
	    la (cdr (assoc 8 (entget en))))
      (if (and (or (and (= 1 (sslength sb))
			(/= 1 (sslength se))
			(setq pt pb))
		   (and (/= 1 (sslength sb))
			(= 1 (sslength se))
			(setq pt pe))
		   (and (setq pt pb)
			(setq par (setq par (vlax-curve-getParamAtPoint en (vlax-curve-getClosestPointTo en pt))))
			(setq ang (angle (trans pt 0 1) (trans (vlax-curve-getPointAtParam en (+ par (if (= (fix par) 0) 0.1 -0.1))) 0 1)))
			(not (command "_.INSERT" *cap-block* "_s" 5 "_none" (trans pt 0 1) (angtos ang)
				      "_.CHPROP" "_L" "" "_La" la ""))
			(setq pt pe))
		   )
	       (setq par (setq par (vlax-curve-getParamAtPoint en (vlax-curve-getClosestPointTo en pt))))
	       (setq ang (angle (trans pt 0 1) (trans (vlax-curve-getPointAtParam en (+ par (if (= (fix par) 0) 0.1 -0.1))) 0 1)))
	       )
	(command "_.INSERT" *cap-block* "_s" 5 "_none" (trans pt 0 1) (angtos ang)
		 "_.CHPROP" "_L" "" "_La" la ""))))
  (vla-endundomark doc)
  (princ)
  )

 

 

Message 24 of 46

Edwin.Saez
Advisor
Advisor

@ВeekeeCZ,

 

perfect thank you very much for your time and help.. Smiley Happy

Edwin Saez


LinkedIn / AutoCAD Certified Professional


EESignature


 


Si mi respuesta fue una solución para usted, por favor seleccione "Aceptar Solución", para que también sirva a otro usuarios.

0 Likes
Message 25 of 46

Kent1Cooper
Consultant
Consultant

@john.uhden wrote:
When you say "side" I presume you really mean "end."
I don't have any experience using ssnamex, but I like learning.
So... if the selection is by fence or single selection, then insert at only
the closest end to the point of selection, right? If by window or
crossing, then insert at both ends, right? ....

This can actually be done with the (ssnamex) function, if you want that capability.  If you want it to work as described above, as you appear to have confirmed in Post 20, the current accepted-solution code doesn't do that, but only checks whether the ends of Polylines are "free" of other nearby stuff within some tolerance, and adds Blocks to any "free" ends, regardless of how the Polylines were selected.

 

But it could be made to work that way, because (ssnamex) will return a list that can distinguish in what way a given object was selected.  So it can know whether you picked on one, and find the nearer end, or whether it was selected with a fence, and find the nearer end to where the fence crossed it, or whether it was just part of a Window/Crossing selection, and find both ends.  So it could put one on only the end selected by pick or fence on a Polyline selected in those ways, even if the other end is also "free".

 

That is doable, but before trying to work it out, do you really want that functionality in favor of what the current accepted solution does?  Also, it could be made to add them at the ends of other objects than Polylines, if you can use that.

Kent Cooper, AIA
Message 26 of 46

john.uhden
Mentor
Mentor
Thank you, Kent, for putting into words what I was thinking. It seems
though that the OP was pleased with another response, so maybe we will
revisit this some time in the future.

John F. Uhden

0 Likes
Message 27 of 46

Edwin.Saez
Advisor
Advisor

@Kent1Cooper,

 

It conducting routine tests, I found that there are cases where places the block on the side of the polylines I do not wish since they are not always together, then, cases occur as show in the pictures.
If you can make what you say, I would like and I appreciate that you can solve it, and have the routine such as you describe.
I can mendiante "fence" or Window / Crossing the block selection only be placed on the side closer to the polyline / line.
It could also set the scale of the block before placing it?

 

would also accept your answer as a solution Smiley Happy
thanks for your help

 

error (2).png

Edwin Saez


LinkedIn / AutoCAD Certified Professional


EESignature


 


Si mi respuesta fue una solución para usted, por favor seleccione "Aceptar Solución", para que también sirva a otro usuarios.

0 Likes
Message 28 of 46

marko_ribar
Advisor
Advisor

@Kent1Cooper wrote:

@john.uhden wrote:
When you say "side" I presume you really mean "end."
I don't have any experience using ssnamex, but I like learning.
So... if the selection is by fence or single selection, then insert at only
the closest end to the point of selection, right? If by window or
crossing, then insert at both ends, right? ....

This can actually be done with the (ssnamex) function, if you want that capability.  If you want it to work as described above, as you appear to have confirmed in Post 20, the current accepted-solution code doesn't do that, but only checks whether the ends of Polylines are "free" of other nearby stuff within some tolerance, and adds Blocks to any "free" ends, regardless of how the Polylines were selected.

 

But it could be made to work that way, because (ssnamex) will return a list that can distinguish in what way a given object was selected.  So it can know whether you picked on one, and find the nearer end, or whether it was selected with a fence, and find the nearer end to where the fence crossed it, or whether it was just part of a Window/Crossing selection, and find both ends.  So it could put one on only the end selected by pick or fence on a Polyline selected in those ways, even if the other end is also "free".

 

That is doable, but before trying to work it out, do you really want that functionality in favor of what the current accepted solution does?  Also, it could be made to add them at the ends of other objects than Polylines, if you can use that.


@Kent1Cooper

 

If you really plan to write the code, I would rather suggest the following :

As posted DWG has line/polyline entities with various linetype property applied, maybe better approach is to cycle through selection set of curves user defined and acquire only those curves that have point of intersection obtained with Intersectwith method with curve(s) from sel. set and user defined curve imitating crossing/fence selection (this could be SPLINE or PLINE that user specifies through command call)... Then this point of intersection could be used in acquiring appropriate end point that is closest (assuming that curves from selection set are opened) and finally by iterating through sel. set, command INSERT could be applied with specifications of appropriate insertion point, scale factor and rotation angle... In the end dummy - helper curve (crossing/fence) is erased and hopefully task is completed in desired way as OP request stated...

Marko Ribar, d.i.a. (graduated engineer of architecture)
0 Likes
Message 29 of 46

john.uhden
Mentor
Mentor

I should learn the intricacies of ssnamex anyway, but how do we incorporate the scale?  Ask for the scale, or use DIMSCALE, or maybe some constant?

I probably couldn't get to it right away.  We are making a day trip to see one of our granddaughters tomorrow.

John F. Uhden

0 Likes
Message 30 of 46

ВeekeeCZ
Consultant
Consultant

@Edwin.Saez.Jamanca wrote:

... 

It conducting routine tests, I found that there are cases where places the block on the side of the polylines I do not wish since they are not always together, then, cases occur as show in the pictures

... 

 


Although I do understand the need to have a tool which place a block exactly where you pick... Don't give up on the solution you have so easily. Following lines defines a size of space (a square) where it tests the existence of objects (by window crossing selection). Red numbers are the diagonal distance from center (end or start point) to upper-right corner or to lower left corner of this square... Try to make it bigger if this fails.

 

	    sb (ssget "_C" (polar (trans pb 0 1) (* pi 0.5) 3) (polar (trans pb 0 1) (* pi 1.5) 3))
	    se (ssget "_C" (polar (trans pe 0 1) (* pi 0.5) 3) (polar (trans pe 0 1) (* pi 1.5) 3))
0 Likes
Message 31 of 46

john.uhden
Mentor
Mentor
Well, I'm not get anything done today. Off to visit one of our
granddaughters for the day.

John F. Uhden

0 Likes
Message 32 of 46

Kent1Cooper
Consultant
Consultant

@Kent1Cooper wrote:

This can actually be done with the (ssnamex) function, if you want that capability.  If you want it to work as described above, as you appear to have confirmed in Post 20, the current accepted-solution code doesn't do that, ....

 

But it could be made to work that way, because (ssnamex) will return a list that can distinguish in what way a given object was selected.  So it can know whether you picked on one, and find the nearer end, or whether it was selected with a fence, and find the nearer end to where the fence crossed it, or whether it was just part of a Window/Crossing selection, and find both ends.  So it could put one on only the end selected by pick or fence on a Polyline selected in those ways, even if the other end is also "free".

....


Here's what I mean.  Lightly tested, but this works for me in your sample drawing [subject to the Note below].  It uses (ssnamex) on the selection, and looks at each entry in the resulting list.  It knows how you selected each Polyline, even if you mix different selection methods in the same running of the command.  When it finds one that was selected by either individual pick or with a Fence, it realizes there's a "closer end" on the Polylines, figures out which end the pick point or the Fence crossing point is closer to, and Inserts a Block on only that end.  If it finds one selected by W / C / WP / CP, for which there is no "closer end," it puts Blocks on both ends.  [I haven't experimented with selecting the same Polyline more than once by different methods in the same running of the command.]

 

[There are additional kinds of entries in the (ssnamex) returned list, about things like the definitions of polygons used in W/C/WP/CP selections, but they start with different numbers than the ones that identify the two categories of types of selection, so it just ignores them.]

 

NOTE:  I adjusted one thing in your sample drawing to get it to work right.  The Block itself is defined as Unitless, but the drawing had its insertion scale ["Units to scale inserted content:" in the Insertion scale area of the UNITS dialog box] set to meters, which forced the A-tapa Blocks to be tiny, even with the code specifying a scale of 5 as in the example.  I could select them and their scale was 0.127 in the Properties box, and I could change them collectively to 5 there, and they would be right.  But I changed that setting in Units to also be Unitless, and it works as expected.  I'll let you deal further with that issue, since it will vary depending on Units settings in individual drawings.  You may want to change the units designation in the Block definition, rather than the setting in a given drawing.  Or you might increase the specified scale in the code to compensate.

 

(defun C:ATapaEnds (/ ss ent pt start end dist inspt rotpt)
  (if (setq ss (ssget '((0 . "LWPOLYLINE"))))
    (foreach item (ssnamex ss)
      (cond
        ( (member (car item) '(1 4)); selected by pick or Fence
          (setq
            ent (cadr item); the Polyline
            pt (osnap (cadr (nth 3 item)) "_nea")
              ; pick point or Fence-crossing point [forced to precisely on ent]
            start (vlax-curve-getStartPoint ent)
            end (vlax-curve-getEndPoint ent)
            dist (vlax-curve-getDistAtPoint ent pt); where along it
          ); setq
          (if (> (- (vlax-curve-getDistAtPoint ent (vlax-curve-getEndPoint ent)) dist) dist)
            ; pick or Fence-crossing point closer to start than end
            (setq ; then
              inspt (vlax-curve-getStartPoint ent)
              rotpt (vlax-curve-getPointAtParam ent 1)
            ); setq
            (setq ; else [closer to end]
              inspt (vlax-curve-getEndPoint ent)
              rotpt (vlax-curve-getPointAtParam ent (1- (vlax-curve-getEndParam ent)))
            ); setq
          ); if
          (command "_.insert" "A-tapa" "_scale" 5 "_none" inspt rotpt)
        ); pick / Fence selection condition
        ( (member (car item) '(2 3)); selected by W, C, WP, CP
          (setq ent (cadr item)); the Polyline
          (command
            "_.insert" "A-tapa" "_scale" 5
              "_none" (vlax-curve-getStartPoint ent)
              "_none" (vlax-curve-getPointAtParam ent 1)
            "_.insert" "A-tapa" "_scale" 5
              "_none" (vlax-curve-getEndPoint ent)
              "_none" (vlax-curve-getPointAtParam ent (1- (vlax-curve-getEndParam ent)))
          ); command
        ); W/C/WP/CP condition
); cond ); foreach ); if ); defun (vl-load-com)

No error handling, or the usual other bells and whistles, yet.

 

Kent Cooper, AIA
Message 33 of 46

Edwin.Saez
Advisor
Advisor

@Kent1Cooper,

 Thanks for the help but I get this error

 

Command: ATAPAENDS
; error: too few arguments

Edwin Saez


LinkedIn / AutoCAD Certified Professional


EESignature


 


Si mi respuesta fue una solución para usted, por favor seleccione "Aceptar Solución", para que también sirva a otro usuarios.

0 Likes
Message 34 of 46

Kent1Cooper
Consultant
Consultant

@Edwin.Saez.Jamanca wrote:

@Kent1Cooper,

 Thanks for the help but I get this error

 

Command: ATAPAENDS
; error: too few arguments


Sorry about that -- I wrote and tested it in a file without "wrapping" the operations in a Command-name definition, so just loading it ran it.  Then before posting it I added the Command-name (defun) wrapping, and mistakenly didn't include the slash at the beginning of the localized variables list at the beginning.  You got to me in time to be able to Edit the Post to correct that.

Kent Cooper, AIA
0 Likes
Message 35 of 46

Edwin.Saez
Advisor
Advisor

@Kent1Cooper,

 

Do not place the lock on the polyline layer where it is placed.
Not always, the block is placed, there are cases where it remains empty.

Edwin Saez


LinkedIn / AutoCAD Certified Professional


EESignature


 


Si mi respuesta fue una solución para usted, por favor seleccione "Aceptar Solución", para que también sirva a otro usuarios.

0 Likes
Message 36 of 46

john.uhden
Mentor
Mentor
Thank you, Kent. I really didn't have time to get to it.

John F. Uhden

0 Likes
Message 37 of 46

Kent1Cooper
Consultant
Consultant

@Edwin.Saez.Jamanca wrote:

....

Do not place the lock on the polyline layer where it is placed.
Not always, the block is placed, there are cases where it remains empty.


The Layer part is easy enough to add, once we know it does what you want otherwise.  On the missing Blocks, post a drawing in which it doesn't put Blocks on some ends.  For example, are all object LWPolylines, or do you need it to include "heavy" Polylines, and/or possibly Lines?

Kent Cooper, AIA
0 Likes
Message 38 of 46

john.uhden
Mentor
Mentor

Heavy, or light, or 3D, or lines shouldn't make any difference when using vlax-curve functions.  Even splines and trimmed ellipses, I think; just not circles.

John F. Uhden

0 Likes
Message 39 of 46

Edwin.Saez
Advisor
Advisor

@ВeekeeCZ,

 

I worked fine by changing those parameters.
Could you do something about the errors that I show in the images?
In the case of the polyline with continuous line type, it could be excluded to place the blocks?
Perhaps adding some restriction when you select the polylines of a predefined layer, do not consider it at the time of placing the blocks.

- Could one also configure the scale before placing the blocks?

 

thanks for your help Smiley Happy

Edwin Saez


LinkedIn / AutoCAD Certified Professional


EESignature


 


Si mi respuesta fue una solución para usted, por favor seleccione "Aceptar Solución", para que también sirva a otro usuarios.

0 Likes
Message 40 of 46

Kent1Cooper
Consultant
Consultant

@john.uhden wrote:

Heavy, or light, or 3D, or lines shouldn't make any difference when using vlax-curve functions.  Even splines and trimmed ellipses, I think; just not circles.


Not for certain things, but the code [as with some others on this thread] filters for LWPolylines only, so it would need to be altered to accept other types, and its rotation angle element would need to use the first-derivative approach rather than find the next or previous vertex by parameter value.

Kent Cooper, AIA
0 Likes