Placing block reference using current block reference points in Civil 3D using Dynamo and python

I am new to dynamo, have used python a bit. I am attempting to automate a process in Civil 3d by using dynamo and possibly python or vba. I begin with a file such as this


The blue and white are reference blocks (cannot assume on same layer) which will be used as reference points for my cad block created in another file. The green are other block references (therefore cannot just grab all block references)

2 cases for block placement:

  1. (Not optimized) 1 block reference overlaying the current block references (sometimes the block references extend past the given block references which is ok)
  2. (Optimized) must use length of row from given file and match to the best fit row of mine ! (image a triangle of lengths of cad blocks)

In civil 3D, general procedure is

  1. check that given block reference and my cad block both in feet (sometimes given reference block drawing says its in feet, but when compared to my cad block, it is in meters or inches) *we can skip this part in code because its fairly easy to manually check but in the future would like this to be apart of it)
  2. click block reference, and select 2 different types of polyline, right click select similar,
  3. copybase point 0,0,0 and paste into new dwg with drawing template
  4. save the file per parent folder/ excel inputs
  5. Open new dwg and creating my reference block using .scr
  6. Determine whether case 1 above or case 2
  7. Case 1: copy and pasting my blocks over the other blocks using bottom left corner
    Case 2: copy and pasting my blocks from triangle that are best fit (usually very close fit)
  8. load lsp file, run specific command i call T_Analyze
  9. Update drawing space from excel file

My thoughts in creating this in dynamo:

  1. Select Object to pick supplied reference block
    Select Object boxes to pick major and minor polylines i need
    python code to select similar like in civil 3d
  2. python code to copybase like in civil 3d, paste in new file with my dwg template
  3. pick reference block again or have them all saved on certain layer, obtain left most bottom point and right most bottom point
  4. Ask user if optimized or not
  5. if not optimized, grab my reference block from another dwg
    if opt, used triangle of blocks from another dwg
    would likely measure the length of the cad blocks that are next to each other using the reference points, then going through an array of lengths for my cad block lengths, choosing best fit, copy and paste using bottom left reference point
  6. Python to load .lsp file and run command? not sure on that one

If you have any questions let me know and I appreciate any assistance you could provide, because this has been quite a challenge for me thus far

Hi @tpitera,

Welcome! This is quite complex indeed. I’ve read through a few times and still have a little trouble understanding. Would you be able to upload the applicable sample DWGs and also a screen recording of the current process?

unfortunately i cannot provide dwgs. to start off, just create rectangles and make them block references. then create a new rectangle nearly the same size with a plus inside it to represent my reference block. if the provided reference blocks are very close that is a row, more than 25 ft of space would be considered a new row. if you replicate my image (each box is own reference block), and if your familiar with civil 3d you will know the select similar and other references. I tried to be as clear as i could be. if you have a more specific question, im happy to answer it. i know how to perform this in civil 3d well, it is replicating civil 3d commands in dynamo to automate the process that I am having the most difficulty with. So if you know any part of this, for example, breaking down a reference block to find the bottom left point and bottom right point, then just answer that question/ part. if we all work together, perhaps we can solve this thing.

OK following are some quick thoughts. I recommend that you download the Civil 3D Toolkit package (I’ll refer to it as “Toolkit”) if you don’t already have it.

Sounds like you’ve got this part - use the Select Object node. There is a node in the Toolkit to select multiple objects if you want to try and consolidate to one step for the user.

I think there could be a non-Python solution for this. If there are pre-set layers that you know ahead of time (or the user can provide them), then you can use the All Objects on Layer node to build the selection in Dynamo. There are other approaches too, like just selecting everything in modelspace and then filtering the list in Dynamo by the properties that you want (layer, linetype, property sets, etc.). The List.FilterByBoolMask is a go-to for this.

This will be tricky. Dynamo currently only works with the current DWG. You might have a look at the Python code @Paolo_Emilio_Serra1 wrote in this post:

It looks like your block references are rectangles. If that is true all of the time, then I think the Bounding Box nodes will work here. You can use Object.Extents to get the bounding box for the block references, and then use BoundingBox.MaxPoint and BoundingBox.MinPoint to get the corner points. There might also be opportunity to utilize the block reference insertion point, which you can get with the Toolkit node BlockReferenceExtensions.GetInsertionPoint.

This will take some work as well. The easiest way to get user input is to run the graph via Dynamo Player, but this means that all of the inputs have to be provided at the start. If you want to collect user input at an intermediate step, I suggest looking into the UI.MultipleInputForm++ node from the DataShapes package.

I’m thinking you could use the Block.Import node here.

Here is some quick Python code to send a string to the command line:

import System
from System import *

input = IN[0]

app = System.Runtime.InteropServices.Marshal.GetActiveObject("Autocad.Application")
adoc = app.ActiveDocument

adoc.SendCommand(input)							

OUT = str(input) + " sent to command line"

i do have the toolkit and a few others i told were useful
muti object select might be better, but there are lines in the background that could potentially get grabbed which is why i wanted to replicate select similar
I am originally given this file not knowing what layers are on it. I guess i could make a prestep as select object, select similar, place on layer of my own name and then begin automation, but again just seeing if it is possible to automate this as well, assuming they are not all on same layer as worst case scenario
i will check out paolo’s code, thanks!
I will try bounding box nodes, thanks!
Regarding user input, i will include that when the person is choosing reference block
block import will bring it into the current dwg which is great, but then i have to put them in the right place. also in the optimized there are 100 blocks, so it may get confused which to use. maybe you could clarify further how we could achieve both these situations (lets just assume right now i brought in my cad block or cad blocks triangle into current dwg)
That is awesome regarding sending command through python code, i think this will help the most!

Great great start. this definitely pushes me in the right direction, thanks @zachri.jensen

Once the block is imported to the current DWG, you could create coordinate systems at the desired insertion points and then use BlockReference.ByCoordinateSystem. In my experience this works better than BlockReference.Create.

Do you think that would work?

This may work for non optimized, will have to test and see. one of my problems here is that the dwg file name will change depending on project. In my filepath I have C:\Users\username…*# - Proj name - client*\folder1\current cad dwg. I need to take out the part between the stars so i can automatically generate the cad dwg name. I have done this using an scr file, but dont know how to replicate in dynamo

for the optimized solution, my block reference file looks like this image
my thought was to somehow copy paste from this dwg pictured to my current cad with the block references. I then thought of making each string into an array of distances. I would then measure the distance of the given row of reference blocks, and then check the array to see which is the closest, then follow the insertion method you described above. Thoughts?

Have a look at the String.Replace node.

I’m not really sure - it seems like a workable approach. Maybe give it a try and see if you get stuck.

I’m not really sure - it seems like a workable approach. Maybe give it a try and see if you get stuck.

perhaps you could offer suggestions on cad blocks to use for this solution?

I have about 50 polylines i need to convert to a surface. I have tried the following from Polyline3D to Surface
image


Finally i tried
which says it runs but i see no surface in my civil 3d (Not sure if i should create a new topic for this because it is still apart of this same large project)

Regarding block import you suggested, says value is null. should dwg file name be with .dwg or without? image
So i tried an alternate approach using LinkDwg package. I tried both InsertExternalDWGAsBlock and a combo of ImportBlockFromDWG and InsertByName. neither seem to be working.

Last thing, i am trying to read code of existing dynamo library nodes, specifically the BlockReference.ByCoordinateSystem node, i found this forum post, but still struggled finding it

Any advice on these? Any help would be appreciated

Yes I would break this out to a new topic. It is not really related to the title of this post so it will be hard to find for others.

I believe it should be the full path to the file, including the file extension.

I would break this out to a new topic as well for the same reason mentioned above.

i dont understand why this is not working, it wont find the block references in the model space

That sequence of nodes would be looking for all of the block references of the Model Space block, which there are none. To get all the block references in Model Space, use Block.Objects and filter out everything that isn’t a BlockReference object using List.FilterByBoolMask.

Here’s an alternate approach.

Ok i have decided to post the files so i can be assisted further. the code i got from Run DYnamo Script on entire folder of dwg's which is precisely what i want to do, but in current dwg, posting new block at all location points. Attached is my civil file, new block reference file and dynamo i have so far
https://drive.google.com/drive/folders/1regRK7XlI97fpSzfEOJgnd99v5VDnwWf?usp=sharing

Hi @tpitera,

Thanks for sharing the files. You’ve done a great job outlining the details of what you’re trying to accomplish, but I am a little unclear of the end goal. All of the steps you mentioned previously will become important when considering the details of the algorithm, but it would help my understanding if we can step back a little bit and look at the big picture.

First I’m going to break down what I am seeing (i.e. the inputs to the problem).

In TEST_Dynamo.dwg, it looks like there is a grid pattern of solar panels arranged on a topo surface with relatively consistent spacing. Furthermore, they seem to be arranged so that they fit within a boundary. Is this a correct assumption?

I see that these panels are blocks with non-descriptive names that contain 3D solids. The insertion point for this block is in the lower left corner.

In testBlockRef.dwg, I see a single reference of a block called test_block. This block has an insertion point that is not located near the rectangle.

So, given these pieces of information, can you briefly summarize the end goal? Some guesses that I have based on your previous outline:

  1. Continue placing the panels to fill the space within the boundary (i.e. a space optimization problem)
  2. Analyze if the provided panel arrangement meets certain criteria and report the results

Thanks in advance for helping me understand :slight_smile:

Correct!

This is not always the case. what we know is that from most likely the insertion point is bottom left corner and looks like a square from top view, they are block reference with any name (unknown)

we can change insertion point of this file, but considering the block is being copied and pasted, it doesnt really matter where insertion point is.

Take a received dwg that has lets say 100 block reference in any formation (unknown) (provided dwg is one possible formation) and insert my block reference at same points. The end goal of this is a slope analysis => convert poly line to Tin surface. Place my cad blocks in same locations as given. Then run .lsp and run a specialized command i created. this completes the program.
Does that help? If you want, i can send you a video privately that does the steps in civil 3d (if that helps)

OK so the constant point we always want is the bottom left corner of the objects within the block, not necessarily the insertion point?

You are wanting to copy/paste this so that the lower left corner matches the point mentioned above, correct? If so, then I think the insertion point does matter and we should put it in the lower left corner so it is easier to line up.

OK I am starting to understand better now, thanks! Yes, if you’re able to send a recording, that would be very helpful.

yep you got it. i want the bottom left of the lines in the bock reference, i was just trying to make it easier by using insertion point. I am basically doing a block replace but keeping the old blocks so i can check for error. also sometimes the provided block reference do not match exactly with my block reference width, in which case neither insertion point or bottom left of block reference would work. I would have to take the total distance of one row, then measure my block width with a half of a foot spacing and get the closest approximation. but again, i am trying to start with the simplest solution. The main question is in my code, why is block reference from other dwg not being brought in and placed at locations from dynamo.

please send me your email

Can you send via Google Drive or a private message on the forum?