Create associative path array with an inserted block

Create associative path array with an inserted block

rebPTFNF
Contributor Contributor
2,483 Views
22 Replies
Message 1 of 23

Create associative path array with an inserted block

rebPTFNF
Contributor
Contributor

Hi all,

Trying to create a routine for a Path Array but routine wont even load to test. Looking for some help...

 

Goal:

Create an associative Path Array using a block from an inserted drawing (MyArray_block.dwg).

NOTE: I just have the drawing saved on my desktop so the path will need updating to match your address bar if you test it. Also,  I created a DWG file with a random polyline for testing called (Random_polyline_for_Array.dwg).

 

Steps:

-User either selects an existing Poly line OR creates a new one for the block to be arrayed to. The line will be based on the parameters of the given project so the length will not be know. Therefor the array must be adjustable.

-A drawing containing a block is then inserted and the block is then aligned to the Array Poly line at the start point.

-An associative array is created using the block at a distance of 4 feet apart. blocks will overlap. Length will be unknown which is why it needs to be associative. It can then be adjusted using the grip handle until it fits the project parameters.

 

Please see illustrations attached:

My block:

MyArrayblock.JPG

 

Example of a successful Path Array using this block and a random Polyline:

MyArraypath.JPG

 

My Code:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;; User selects or creates Associative path array using an inserted block;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun C:myarray (/ ln_sel arrayline StartPoint insertpt1 myarrayblock myangle mydistance blksecpoint);;
(vl-load-com)

(setq oldLUNITS (getvar "LUNITS"))

;Set Units to Architectural.
  (setvar "LUNITS" 4)
;Say YES to Polyine edits automatically.
   (setvar "PEDITACCEPT" 1)


;Tell user to select an existing polyline or create a new polyline
(princ "\nSelect an existing Polyline or create a new one: ");command prompt

;User selects existing polyline or draws a new polyline for Associative Path Array. Next, Get start point of that Polyline.

(setq ln_sel (car(entsel "\n Select a polyline:")))

(if (= (cdr(assoc 0 element)) "POLYLINE")
  (progn
    (setq arrayline (vlax-ename->vla-object (car ln_sel )));User saves Polyline
    (setq StartPoint (vlax-curve-getStartPoint arrayline ));save start point
  );Else
(command "_pline" pause); If no poyline selected, User draws a polyline
(setq ln_sel (entget "L" ));save Polyline user either selected or creates
(setq StartPoint (vlax-curve-getStartPoint arrayline )); save start point of array path Polyline
  );end progn
);end IF


;NEXT

;Insert block from a drawing. Insertion point same location as startpoint of the Associative Path Array Polyline
(setq insertpt1 StartPoint)
(command "_insert" "C:\\Users\\B\\Desktop\\MyArray_block.dwg" insertpt1 "" "" "");Insert drawing (saved on desktop for testing purposes)

(setq myarrayblock (ssget "L" )); save the block that was just inserted into drawing

;Preset my second point variables for my inserted block. Picking opposite end
(setq myangle (atoi "90")); Angle = 90 degrees from start point
(setq mydistance (atoi "48")); Distance =  48" (4') from start point

;Make the second known point on block 48 inches at 90 degrees from insert (or start) point
(setq blksecpoint (polar insertpt1 (angle myangle) mydistance)); point one is insertion or start point. Point two is 48" at 90 degree angle

;Now align the block

;Align the block to the Path Array using set points on block
  (if (and (setq blkp1 StartPoint);block insertion point
           (setq blkp3 blksecpoint); second point on block. 48" distance at 90 angle.
       (setq blkent myarrayblock);inserted block
       (setq blkp2 StartPoint); Second alignment point is same as start point (or rotation point)
       (setq blkp4 (osnap (cadr blkent) "_nea")); snap second block point somewhere on array path polyline
       )
    (command "_.align" blkent "" "_non" blkp1 "_non" blkp2 "_non" blkp3 "_non" blkp4 "" "_No")
  );End if


;Next, Path Array


;Next do an associative path array using the inserted block that has been aligned
(command "arraypath" blkent "" ln_sel "as" "yes" "items" mydistance "" "");; pick Block. Pick line. Distance 48" (4')


;Last, delete the insert block from the drawing
(if (/= blkent nil)(command "erase" blkent ""))

(setvar "LUNITS" oldLUNITS)

);end

Any assistance or suggestions are greatly appreciated!!!

Thanks all

0 Likes
2,484 Views
22 Replies
Replies (22)
Message 2 of 23

ВeekeeCZ
Consultant
Consultant

Well, I tried but hit the wall.

 

For some reason, PATHARRAY creates an array from the other end of the curve. Can't make it behave by the usual tricks I know. ‌‌It might take some time to figure this out that I don't have at the moment.

 

(defun c:APB ( / n d s i e p a b)

  (setq n "Myblock")
  (setq d 48)
  
  (if (setq s (ssget))
    (repeat (setq i (sslength s))
      (and (setq e (ssname s (setq i (1- i))))
	   (setq p (vlax-curve-getstartpoint e))
	   (setq a (angle '(0 0 0) (vlax-curve-getfirstderiv e 0)))
	   (setq b (entmakex (list '(0 . "INSERT") (cons 2 n) (cons 10 p) (cons 50 a))))
	   (initcommandversion)
	   (vl-cmdf "_.arraypath" b "" e "_b" p "_i" d "" "")
	   (entdel b)
	   )))
  (princ)
  )

 

Edit: I added a quick mod of my pseglen HERE  if you give up on arraypath, as I did. I would also recommend modifying your block the same way I did and adding a block to the searchable path.

0 Likes
Message 3 of 23

jayhar
Advisor
Advisor
Accepted solution

The updates include adding a check for the curve's direction and adjusting the ARRAYPATH command to insert the blocks from the correct end of the curve. If the curve is reversed, the array is created from the endpoint instead of the start point.

 

Please Subscribe YouTube Channel
https://www.youtube.com/channel/UCclj8v9vHQiFa8_DriuAk3w

Please Mark the Post or Posts as Solution(s) to help others find the answer quickly.
0 Likes
Message 4 of 23

rebPTFNF
Contributor
Contributor

Thank you for your input. I will check it out!

0 Likes
Message 5 of 23

Sea-Haven
Mentor
Mentor

Gave it a try with the dwg from here, https://www.cadtutor.net/forum/topic/94049-create-associative-path-array-with-an-inserted-block/

SeaHaven_0-1732601191688.png

Not sure if that is what is wanted. See other post for different image result. 

 

 

(setq n "poly")

 

Ps removed initcommand

As mentioned in other post block needs bedit move to 0,0 for correct end point and rotated 90 degrees to right. 

 

Need @rebPTFNF to post a real dwg showing what is required, not lines and a block.

0 Likes
Message 6 of 23

rebPTFNF
Contributor
Contributor

Thank you all. When I try the routine, Im having trouble with the block matching the alignment of the polyline for some reason. It doesn't seem to align like what I see in Sea-havens example.

 

Alignment_issue.JPG

 

 

 

0 Likes
Message 7 of 23

ВeekeeCZ
Consultant
Consultant

You don't mention what method/routine you used to create the posted image, but it's evident that simply rotating the geometry in the block should solve the problem - this has been mentioned repeatedly.


As I already wrote, and no one has proven me wrong yet (I wish someone had), according to my tests, ARRAYPATH is not suitable for automating this process. It is unpredictable.

 

At this point, I see the only solution as creating the array manually, possibly using the routine I posted earlier. 

0 Likes
Message 8 of 23

Sea-Haven
Mentor
Mentor

I agree with you @ВeekeeCZ need to see a real dwg AGAIN ASKING @rebPTFNF post what your answer should look like, even if you do manually.

 

2 versions have been posted, chain version and an arraypath version.

0 Likes
Message 9 of 23

rebPTFNF
Contributor
Contributor

Sorry for the delay. I live in the U.S and this is a holiday week with family so time somewhat limited on my end.  I did manage to create an example as requested. I am attaching a typical project DWG (only the relevant parts to keep it clean and understandable) as an example of what my task is. In this typical example, The project changed design and had to be redone so thought this was a good example to show. The first design shows two shapes that need to be surrounded by the 4' long blocks (like a chain). The goal is to surround them closely. Which is shown in the completed box. This is a finished example. As stated, the design ended up changing  and so a redesign of the blocks needed to be done as well.  Currently in my office we are doing this work manually. Bring in a block and start copy and rotating them in a chain fashion to surround the shapes. Express tools makes it a little quicker but still... If the design changes the blocks will have to be reshaped around them. They may change the design in the distant future as well (a year or two). I am thinking there is got to be a more efficient way to do this than manually every time. My thought. Just draw a polyline around the shapes of the project. attached and align the 4' block. Make an associated Path array and adjust where needed. Then when the design changes, its just a matter of adjusting the array instead of redoing it all. Hopefully this project example will help shed more light on what I hope to accomplish... Again, thanks for any assistance. 

Project_Example.JPG

0 Likes
Message 10 of 23

ВeekeeCZ
Consultant
Consultant
Accepted solution

With my already posted Pseglen and simple grrread CIRCLES func I can do something like this. If that makes sense to you and nobody else posts something more advanced, I'll make some adjustments and post it.

 

 

(defun c:fline ( / s p e p1 p2 l s f done)

  (setq f 48
	p (getpoint "\nSpecify point: ")
	s (ssadd))

  (while (not done)  
    (command "_.line" "_non" p pause)
    (if (> (getvar 'cmdactive) 0)
      (progn
	(command "")
	(setq e (entlast)
	      p1 (getpropertyvalue e "StartPoint")
	      p2 (getpropertyvalue e "EndPoint")
	      l (distance p1 p2)
	      l (max f (* f (fix (/ l f))))
	      p (polar p1 (angle p1 p2) l))
	(command "_.lengthen" "_t" l (list e p2) "")
	(ssadd e s))
      (progn
	(initcommandversion)
	(command "_.join" s "")
	(setq done T))))
  (princ)
  )

 

0 Likes
Message 11 of 23

rebPTFNF
Contributor
Contributor

Hey all.

Sorry again for the late reply's. I really appreciate everyone's input and I think you have created great solutions.

BeekeeCZ. The Fline routine works great keeping the lines to 48" increments. When i run your fencing it always works out perfect. I also tried the array version along with Jayhar's additions (Thank you Jayhar for the curve direction addition). You guys are correct about the Array being a bit unpredictable. But when it does work it does give the ability for future adjustments. I will keep playing with that option as well.

BeekeeCZ: I combined your Fline and fencing code into one routine and it works. Thank you. I will attach for your review.  Let me know if you see any issues with my combo attempt. I just altered a few variable names so it hopefully wouldn't cause any issues. maybe not needed in the end.  ** The strange thing is that I cant just drop the LISP routine file into my drawing or load from the Visual LISP Editor and run. Both times it errors out. The only way i get it to load  is to copy the code into a new blank file in the editor, highlight all and say run selected.. Then it loads no problem....Any ideas why?

The last thing I will work on is bringing in the myblock and adding that for "an all in one" routine... hopefully. I think Lee mac had something I saw about that somewhere. 

 I think this is a great solution everyone! Thanks!😁

0 Likes
Message 12 of 23

ВeekeeCZ
Consultant
Consultant
Accepted solution

Your combined version works if that's what you want, except that you copied-pasted my nickname, which was not a smart move. I've made just a few enhancements to be more efficient. If you want to autoload your block, just add it  between the searchable paths, and your issue is solved (can't place it there directly; it needs to be wblocked or just a simple dwg (w/o block) named with the block name.

 

Anyway, I've promised to make some enhancements so that you might try it. There are options there... the names are given, but the functionality is a bit different from the default behavior.

0 Likes
Message 13 of 23

rebPTFNF
Contributor
Contributor

Wow, that was a great enhancement. I was working on having the inserted block and line auto selected but this is even better. Impressive work! Its completely automated now...

 

Before seeing your post, I had just added in real basic code at the beginning and end to insert the drawing with the block and then delete the block when done.

 

;Insert block into drawing
(if (= Myblock nil)(command "-insert" "C:/Path..../Path..../MyArray_block.dwg" "0,0" 1 1 0))

......

.....

;Delete inserted block
(setq dlblk (ssget "X" (list '(0 . "INSERT") (cons 2 "Myblock"))))
(command "erase" dlblk "")
(command "-purge" "B" "Myblock" "N" "")
(command "_regenall")

 

I don't know if this simple method will cause any issues if I want to redo the routine more than once in the same drawing. Hopefully not but will need to test...

 

Thanks again for all of your assistance and your solution works great!

🙂

 

 

 

 

0 Likes
Message 14 of 23

ВeekeeCZ
Consultant
Consultant

It's not necessarily bad, just unnecessary.

Why you asking... do you see some advantage over my code that I don't?

0 Likes
Message 15 of 23

Sea-Haven
Mentor
Mentor
Accepted solution

Re is poly block in current dwg, posted elsewhere today. Uses Steal.lsp by Lee-mac.

 

 

(if (= (tblsearch "Blocks" "Poly") nil)
(progn
(if (not stealall )(load "StealV1-8.lsp"))
(Steal "C:\\My Folder\\MyDrawing.dwg" 
   '(("Blocks" ("Poly")))
)
)
)  

 

 

 

0 Likes
Message 16 of 23

rebPTFNF
Contributor
Contributor

My apologies.  I think I may have miss understood your advice below:

"If you want to autoload your block, just add it between the searchable paths"

 

I thought that you meant I still needed to add code to insert a drawing containing the block needed but place it in a specific spot.

I saw the table search in your latest routine looking for the block saved as B (myblock) but wasn't sure about the path part location.

If it is brought in by adding a searchable path, can the initial block brought in also be removed as well without deleting all of the other blocks with the same name.Thats where i have difficulties. Perhaps I am not bringing in the block as you intended....

 

Thanks Seahaven for the advise you gave as well. I have see Lee's steal command in my online research's and ofourse on his site.... I will try it out!

 

Thank you both!

0 Likes
Message 17 of 23

Sea-Haven
Mentor
Mentor
Accepted solution

We had 100+ blocks probably more, so make the "poly" a single dwg will make life so much easier, just use wblock and save "poly.dwg". keep all your little blocks in one directory and add that directory to your support paths, then can insert with name only used. -insert "poly". Options Files Support.

0 Likes
Message 18 of 23

rebPTFNF
Contributor
Contributor

Great solution. Just to recap: Save "myblock" as a wblock file in a main directory folder. Insert "myblock" as a wblock into poly.dwg. The "myblock" can then be grabbed out of the Poly.dwg file using Lees script and inserted into my current project drawing. This way I can fill poly.dwg with an assortment of wblocks and only need to call up poly.dwg and the wblock name.  I hope I got that right... Let me know if I misinterpreted the steps. I will try this out when I get back into town next week. Again, Thanks again for everyone's assistance!

0 Likes
Message 19 of 23

ВeekeeCZ
Consultant
Consultant

Ou boy, last @Sea-Haven  explanation looked so promissing... this is how your dwg should look.

0 Likes
Message 20 of 23

rebPTFNF
Contributor
Contributor

Cool.  Not a block in the separate DWG file but inserted into poly.dwg as a wBlock. Hope I got that right. Then Lee's script pulls that into my project drawing.

Can this method help with the removal of the original inserted wblock called "myBlock"  into my project by chance? Not a big deal if not. I have to count the "myBlocks" for pricing quotes. How many there are that make up the "chain" so to speak for each project (since its always different and the blocks represent real world items being sold). I was just going to do a  "Select similar" to get the number of items and then reduce the number listed by one and delete the original block inserted at 0,0. I was thinking if there is a way to just rename the entity located at 0,0 and then delete entity by its new name,  leaving the rest of the chain with the original named blocks intact for counting. Is that a good way to approach this? Or because its a wBlock, all blocks in the "chain" would be renamed as well and then all would be deleted...wBlock is a reference being pulled from another file so Im guessing you cant rename it in the actual project file now that i think about it. Not sure the best way to solve that one. But, its a small extra step so not a big deal....

 

BeekeeCZ. Your script really works great!

0 Likes