Help: Script that copy's names from one child layer to another


#1

I have an idea to quick and easily change a lot of layer names, I have layers where the names are correct, and some layers where the names are wrong, All names of the _3D Layers are correct, _2D are wrong, but only in Number, Amount and having the text “[BLOCK]” behind it. The center of all strings of text are correct.

I want my script to look for the names of child layers from 2D, look the counterpart with the correct Number and amount, and then just change the 2D child layer name, to the same as the 3D name.

I hope this is clear enough, otherwise there is also an example in the script portion.

Glance your eyes over my “proposed” script and tell me if this has any chance of working (if written correctly)

//////////////////////////////////////
//
// In below example you see there are 3 things that change, Number, Amount and the [BLOCK] portion is removed.
//
// Number;ObjectNumber;Name;Dimensions;Amount;
//
// This script should take the name of child layer from the _2D layer, find the relating name from the _3D layer, and then copy the _3D Layers child name over the _2D layers child name.
//
//Example
//22.003.501_2D
//	1;TB-20 16 5;Washer;Ø20xØ16x2.5;1;[BLOCK]
//	1;BBE-2259393;Body;30x20x60;1;[BLOCK]
//
//22.003.501_3D
//	01;TB-20 16 5;Washer;Ø20xØ16x2.5;4;
//	02;BBE-2259393;Body;30x20x60;2;
//
//Should become:
//
//22.003.501_2D
//	01;TB-20 16 5;Washer;Ø20xØ16x2.5;4;
//	02;BBE-2259393;Body;30x20x60;2;
//
//22.003.501_3D
//	01;TB-20 16 5;Washer;Ø20xØ16x2.5;4;
//	02;BBE-2259393;Body;30x20x60;2;
//
///////////////////////////////////////////////////

$INPUT_P_Layer "Please insert name of parent layer with default child-layer amounts"
";22.003.501_2D;"

$INPUT_S_Layer "Please insert name of parent layer with correct child-layer amounts"
";22.003.501_3D;"


$INPUT_P_Layer

//This script should check all child layers of $INPUT_P_Layer once

	$TargetToReplace = Search child layer for first hit of:
		1;*;[BLOCK]
			-> $TargetSource = * of $TargetToReplace result

	$TargetToReplaceWith = Search $INPUT_S_Layer child layers for $TargetSource (CHECK IF ONLY 1 result, otherwise print/report the given results)

	$CorrectName = Take full layer name of $TargetToReplaceWith

	Replace Initial found child layer with $TargetToReplace option and replace it with $CorrectName
	
PRINT: process is completed and how many results it found / replaced (if possible)

(Giulio Piacentino) #2

[EDIT]
I see this was discussed here: How to know/ figure out what functions I need (Search & replace names)

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com


#3

That is my own post @piac, but this is something else.

This script has a couple of things that are very much different. I worked out this example including the way I think it should work, to ask/discuss if this is even possible for starters.


(Giulio Piacentino) #4

I see. Then my feeling is that this would be possible. Of course, it’s also a question whether writing the script will take longer than just manually doing the work (how many layer there are, etc).

I think it’s a bit difficult to help because layer names are so complicated and there are just two cases shown, so it’s not easy to generalize. I would say, a possible way to tackle this is via RegEx, or also just splitting the layer name into chunks.

I offer my help on writing the first stub of the script, but it’s highly likely that you will have to improve it in the longer term. So, do you prefer Python or VbScript? Have you ever used other programming or scripting languages?
Could you add a couple of examples of from->to? I do not understand 100% what you need to do.

Thanks,

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com


#5

Hello Giulio,

The reason why manually will be slower is because right now there are around 20 products that have this issue. But the main problem is that Make2D always takes the layer names from the BLOCKS and not from the layer the block-object itself is place in.

I’ve worked myself with Php, javascript, html, and I am planning to learn whichever of the two languages is more versatile.
The complexity of the layer names is covered by entering the Target and Search layers manually. The part that are to be searched are quite definable.

the sublayers of the _2D layer that have data that needs to be changed always start with “1;” and always end with “;[BLOCK]”.

As soon as the name of said sublayer is changed it will not have the “[BLOCK]” part anymore and will not be picked up anymore by the search query.

What would you say the ups/downs are of both languages, and of course, which (or both?) language works with strings well, and dissecting them if necessary.

The formatting of layers is always as follows:

[SerialNR]
	[SerialNR_2D]
		1;[variable data C];[BLOCK]
		1;[variable data E];[BLOCK]
		1;[variable data B];[BLOCK]
		1;[variable data A];[BLOCK]
		1;[variable data D];[BLOCK]
	[SerialNR_3D]
		01;[variable data A];
		02;[variable data C];
		03;[variable data D];
		04;[variable data B];
		05;[variable data E];

(Giulio Piacentino) #6

Hi Peter,

so, I think this might be coded in both. The upside of Python is that, in the long run, it will work also on the Mac.

I’ve written a sample script that can be the base point of what I think you want. The main area of uncertainty for me is this: The part that are to be searched are quite definable. But probably you will be able to fix that yourself.

I hope this is helpful. I’ve tested it with the attached file.

import rhinoscriptsyntax as rs

layers = rs.LayerNames()
if layers:
    
    always = False
    for layer in layers:
        
        levels = layer.split("::")
        #we skip all layers that are not at level 2
        if len(levels) != 3: continue
        if rs.IsLayerEmpty(layer): continue #skip empty layers
        new_levels = list(levels) #copy
        
        level1 = levels[1] #get the 2D-3D sublayer part
        if not level1.endswith("_2D"): continue #only tackle _2D layer
        new_levels[1] = level1[:-3]+"_3D"
        
        level2 = levels[2] #get the complicated part
        
        all_bits = level2.split(";") #get tokens that make up the complicated part
        first_bit = all_bits[0]
        last_bit = all_bits[-1]
        central_bits = all_bits[1:-1]
        
        if last_bit != "[BLOCK]": continue #just do something if last bit is [BLOCK]
        
        # if first part is only made up of 1 char, then add 0 in front
        if len(first_bit) == 1: first_bit = "0" + first_bit
        
        new_bits_list = [first_bit]
        new_bits_list.extend(central_bits)
        new_level2 = ";".join(new_bits_list) + ";"
        
        new_levels[2] = new_level2
        new_layer = "::".join(new_levels)
        
        print("The following will be renamed:")
        print("FROM: " + layer)
        print("TO:   " + new_layer)
        
        answer = None
        if not always:
            answer = rs.GetString("...do you agree?", "Yes", ["Yes","No","Always"])
        if always or answer:
            
            if answer == "Always": always = True
            elif (answer is not None) and (not answer.upper().startswith("Y")): continue
            
            level1_full = "::".join(new_levels[:2])
            if not rs.IsLayer(level1_full): rs.AddLayer(level1_full, parent=levels[0])
            if not rs.IsLayer(new_layer): rs.AddLayer(new_levels[2], parent=level1_full)
            
            rs.ObjectLayer(rs.ObjectsByLayer(layer), new_layer) #move all objects to other layer
            
        else: break

(Use the _EditPythonScript command to execute this)

I hope this gives you a good start.
Thanks, kind regards,

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

layers-Peter.3dm (17.9 KB)


#7

Hello Giulio!

Thanks for your time, help and all the comments in the script. After reading and trying out the script I have two questions,

  1. When trying to execute the script nothing happens, neither by running it trough the editor in Debug, or without debug, nor by running it from a file.

  2. I was wondering if this part is essential when thinking it takes the names from the _3D layer anyway:

      if first part is only made up of 1 char, then add 0 in front
     if len(first_bit) == 1: first_bit = "0" + first_bit
    

I think I might have been a bit vague about that part, but as soon as the search found the _3D counterpart with correct data, it can just change the entire name of the corresponding _2D layer.

//22.003.501_2D
//	1;TB-20 16 5;Washer;Ø20xØ16x2.5;1;[BLOCK]
//	1;BBE-2259393;Body;30x20x60;1;[BLOCK]
//
//22.003.501_3D
//	01;TB-20 16 5;Washer;Ø20xØ16x2.5;4;
//	02;BBE-2259393;Body;30x20x60;2;

The names in the _2D layer are alowed to be overwritten as long as the data between the “1;” and “;[BLOCK]” is the same.

So this part:
1;TB-20 16 5;Washer;Ø20xØ16x2.5;1;[BLOCK]

is the same as this part
01;TB-20 16 5;Washer;Ø20xØ16x2.5;4;

the first layer name can be replaced with the second name.


#8

I’ve tried out the script on the test file too,

Here it hits 1 time, but then stops.

If I choose at “…do you agree?”

Yes:
It replaces the first hit only

Always:
It does not replace anything.

I will send you a test file with full names in a pm!


(Giulio Piacentino) #9

Well, in the test file there was only 1 layer to be renamed. As the logic depends from layer names, the script does not make a distinction if the layer contains 1 or 1000 objects (in this case, 2).
I’ve added another layer for a similar test.

layers-Peter.3dm (20.9 KB)

In this case (with two layers to be changed), we are asked twice:

I’ll check what you sent in the PM as well now.

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com


#10

[edit] in code for _ display

Ahh I think I see what it is,

From your example it seems that the script copies the name from the _2D to the _3D layer.

As you can see in the updated test file(s) I've send you it should check what the _3D layer with the same "variable data" has for a name, and copy the entire name of the _3D Layer, and replace the _2D layer with that name.

I've got a feeling we've misunderstood that part.

(Giulio Piacentino) #11

I am not sure how this part could work.
In your example,

1;TQ-40.8354.010;Aerator;Male M24x1.0 (STD) Honeyc. white;Assembly part;1;[BLOCK]

corresponds to

01;TQ-40.8354.010;Aerator;Male M24x1.0 (STD) Honeyc. white;Assembly part;1;

but

1;TD-52 28.5 1.0;Washer;Ø52xØ28.5x1.0;Stainless steel;1;[BLOCK]

does not have correspondences.
[EDIT]…Or actually… You mean that:

15;TD-52 28.5 1.0;Washer;Ø52xØ28.5x1.0;Stainless steel;1;

is the correspondence, right? If this is the case, I think I know what we can do.

Otherwise, I fear you will have to edit the script yourself or devise another logic if the one I came up with does not work for you. The main isssue I am not sure about is how the script can match (and not just add) layers if they do not have precise correspondences.

Thanks, I hope this helps,

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com


#12

Hello Giulio, I do see the corresponding layer, are you sure you don’t see this layer in the file i’ve send you?

_2D item:
1;TD-52 28.5 1.0;Washer;Ø52xØ28.5x1.0;Stainless steel;1;[BLOCK]

_3D item:
15;TD-52 28.5 1.0;Washer;Ø52xØ28.5x1.0;Stainless steel;1;

Also, if a layer does not have any objects does not matter, but as you say if a layer would not exist I would personally just pause the script give feedback what layer causes a problem and choose to continue/abort.


(Giulio Piacentino) #13

I see. I’ll try to have a look at this in the afternoon.

You sent a file with all linked blocks and those blocks are in an “R:” folder that I don’t have. That being said, I think I understand what you mean now.

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com


#14

No rush, I’m already happy everyone here is so helpful! @djordje @piac @Helvetosaur and all others i’m forgetting!

I’m working on manually changing the names at the moment, but there is still a lot to do, and sadly the way make2D works now it will be manually renaming at every new make2D, but hopfully in the new Rhino this will change :slight_smile:


(Giulio Piacentino) #15

I would be very interested in hearing what change would help you. Please, could you elaborate? The main issue is the difference in layer name that requires matching that puzzles me.


#16

In this topic’s first post you can see an example of what the problem is with the make2D in our case.

The problem arises because the Make2D option with “maintain source layers” takes the layers from the contents of the blocks. Rather then the actual layer the block is put in. This is not necessarily wrong behavior from the software but it causes us to have to go in afterwards and change all the prefix numbers and quantities from “1” to the proper amount, and removing the “[BLOCK]” parts of the names.

The prefix number and quantities we’ve set to 1 in the block as a default because they differ per product they are in. While making the products in 3D we place the blocks and move them to new layers with correct names. After this step we create 2D drawings using the “make2D” option.

Our goal would want to have the “maintain source layers” use the names of the layers the blocks are placed in.

I hope this information + the link to the post will explain our problem. The reason why i’m trying to get a script as this one working, is because I’m expecting that the “maintain source layers” option is working as intended, and this is only a problem for us.


(Giulio Piacentino) #17

Thanks for the clear explanation. I’ve reported this wish and usability problem. We might be able to tackle this in a next release of Rhino.
http://mcneel.myjetbrains.com/youtrack/issue/RH-23658

For now, I’ve tested this improved version of the script with the file that you sent me in the PM.
Have a look if it helps, and if it does, please let me know (:

It tries to look up the corresponding layer in any layer name that does not end with [BLOCK]. If it does not succeed, it will alert you. Really, you can try to improve this script to fit your purposes better. Having scripting/programming backgrounds in other languages will definitely help you.

layers-Peter-semicolon-lookup.py (2.7 KB)

Thanks,

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com


#18

Super! The searching the corresponding layers is working great! Feedback is wonderful! Only 1 problem, after running the script I checked the layers and they don’t seem to have changed. Or could it just be the layers need a refresh somehow?

[edit] And I just noticed while running the script, it seems to be deleting the curves that where on the _2D layers where it had matches on. Shall I send you one of the actual files to try it on?


(Giulio Piacentino) #19

Have a look if this helps better.
Thanks,

Giulio

Giulio Piacentino
for Robert McNeel & Associates
giulio@mcneel.com

layers-Peter-semicolon-lookup-specific.py (2.7 KB)


#20
Perhaps this clears things up from the original post, It is really only the names that need to be changed, no objects/layers need to be moved or deleted, just the names of the _2D layers.

//////////////////////////////////////////////////
//
//Example
//22.003.501_2D
//	1;TB-20 16 5;Washer;Ø20xØ16x2.5;1;[BLOCK]
//	1;BBE-2259393;Body;30x20x60;1;[BLOCK]
//
//22.003.501_3D
//	01;TB-20 16 5;Washer;Ø20xØ16x2.5;4;
//	02;BBE-2259393;Body;30x20x60;2;
//
//Should become:
//
//22.003.501_2D
//	01;TB-20 16 5;Washer;Ø20xØ16x2.5;4;
//	02;BBE-2259393;Body;30x20x60;2;
//
//22.003.501_3D
//	01;TB-20 16 5;Washer;Ø20xØ16x2.5;4;
//	02;BBE-2259393;Body;30x20x60;2;
//
//////////////////////////////////////////////////