Jump to content
Developer Wiki and Function Reference Links ×

Unique ID / Number for custom objects with record


Recommended Posts

I don't know if the title was understandable enough, however, here i will try to describe what I am looking to do

In the case below I have polygons / rectangles that have a record, story, and object type. Essentially they need a unique id / number in order for a plan examiner to cross reference that id with the table below.

 

1. Create a worksheet script that changes ID count (as shown below) based on a few parameters and changes a field called ID in a record.

(if that is possible). I know it would either be a record callout or a script callout, so i'm not really sure how to do this.

 

2. Technically the record count can be done without a worksheet now that i am thinking about it because of the unique parameters of each object, story, and count would be able to cover all objects.

Note : the reason the ID is a separate field is because it used for the purposes of a datatag showing graphically what object that is (2nd image below)

 

3. The reason for this request is because using the data-tag count system does not work - it counts all tags not only in the sheet layers but also in the view ports. (unless there is a work around I am not aware of?)

 

image.thumb.png.1c61c3623a4f6dc839be3b2f44b98f5f.png

 

image.png.dd8ed1615c1bc2d76d80a62b53450aa3.png

Edited by Samuel Derenboim
Link to comment
  • Samuel Derenboim changed the title to Unique ID / Number for custom objects with record

You should be able to specify the Criteria of a Data Tag count to only get the tags off a specific or set of specific layers.

 

The usefulness will depends on how your layers are named and which ones you want.

 

Layer Name Contains (or Does Not Contain) [Or Starts with] may give you a smaller number of criteria rows if all your design layers or sheet layers have some similarity in the naming.

 

Ask again if this is not enough.

 

There is no good way to script going from a database subrow to a record that can be picked up by a data tag. You can do it manually, but tying to do it automatically is "challenging".  Let's see who likes a challenge to prove me wrong 😉

Link to comment

Hi Pat, thank you for your response!

When objects are added, what would one do to auto re calculate the incrementing value? Would it be done in the sheetlayer viewport? or would it be done in the worksheet? specifically if one was to do it by 'criteria'

 

I also noticed a script your wrote in a different thread (sorry in advance 🙂 )

Question is :

1. What parameter should i choose to change a field in a record rather than the name of the object (i see only SetName)

2. What is Hd1? is this a rectangle reference?

3. Does the application quit if and only if the object doesn't have a number?

4. For some reason when running this script I still don't get a popup or dialog asking to enter the name of the object

 

Procedure PickAndName;

Var    H1:    Handle;
    X1,Y1,Z1, X2,Y2: Real;
    N1: Integer;
    B1, B2: Boolean;
    
Function CallBack(Hd1:Handle):Boolean;
    Begin
        If GetType(Hd1)=3 then CallBack:=True;
    End;
    
Begin
    N1:=1;
    B2:=False;
    While B2 = False do
        Begin
            TrackObjectN(0, CallBack, H1, X1,Y1,Z1);
            If H1 <> Nil then
                Begin
                    If Command then N1:=IntDialog('Enter Number for this Object.', Num2Str(0,N1));
                    SetName(H1,Num2Str(0,N1));
                    N1:=N1+1;
                End
            Else    B2:=True;
        End;
End;

Run(PickAndName);

 

 

Edited by Samuel Derenboim
Link to comment

@Pat Stanford

Please don't laugh, I made a rough outline of the procedure for the franken-script. Can you please tell me if i'm off, how far i am off, and should i even bother? 😂

 

 

Procedure SetObjectID;

 

 Var
 IDhand: Handle;
 X1,Y1, X2,Y2: Real;
 IDcount: Integer;
 B1,B2: Boolean;

 

Procedure GetIDcount(idhand:handle)

Begin {ID Count Procedure}
 
1 delete all object id's with (this record,this field) {this resets all id's for the Record/ID so that procedure below can begin}


2 pick object closest to origin, set (this field, this record) closest to 0 @ X, Y, or Z in model space
or object closest to origin x,y on screen

 

3 Set (Record, ID) to 1 from picked object


4 {if any objects that have id = 1 while all others do not have any information inside } then setrfield for all objects from handle IDcount with IDcount being equal to IDcount+1 (or other count formula)

The conditions were extrapolated from another script that you wrote shown in the above comment 🙂

Begin
    IDcount:=1;
    B2:=False;
    While B2 = False do
        Begin
            TrackObjectN(0, CallBack, H1, X1,Y1);
            If H1 <> Nil then
                Begin
                    SetName(ID_Handle,Num2Str(0,IDcount));
                    IDcount:=IDcount+1;
                End
            Else    B2:=True;
        End;
        
Begin  {conditions for all objects to be revised}

 ForEachObject(GetIDCount, ((R IN ['Record'])) )

 END;

 

Run(SetObjectID)

Edited by Samuel Derenboim
Link to comment

@Samuel Derenboim  I am not sure I understand what you want, which makes it hard to comment on the script.  It sounds like you just want every object in the drawing to have an "ID Number"  that can be displayed in a Data Tag.

 

So are you going to manually attach the record to the objects you want and delete it from the objects you don't want?

Your initial worksheet above shows not only a sequential number, but also some kind of code (ED, ND, NW). Do you need that? Or is that just stored separately and concattinated in the data tag?

Do you really want/care about the order of the numbering? You specify that you want 1 to be the object closest to the origin, but what do you want after that? To "serial" out from the origin? Do you prefer 2D or 3D?

Your sample worksheet shows the ID numbers with leading zeros, and different numbers of leading zeros. How do you want the decision on the number of IDs (and therefore the left zero padding) to be done?

 

It looks to me like you are going to have to create an array of all the objects, sort it based on distance from the origin and then step through the array assiging the ID numbers.

 

Be glad to work though this with you, but lots of big picture stuff that has to be decided before we can get to implementation details.

 

Link to comment
6 hours ago, Samuel Derenboim said:

I also noticed a script your wrote in a different thread (sorry in advance 🙂 )

Question is :

1. What parameter should i choose to change a field in a record rather than the name of the object (i see only SetName)

 

SetRField( Hd1, Record, Field, Value)

 

 

6 hours ago, Samuel Derenboim said:

2. What is Hd1? is this a rectangle reference?

Hd1 is a Handle. This is a unique reference to a specify object in a VW drawing. for that launch of VW. It may be different the next time VW is run. Handles are the standard way of referencing and object in VW if you can't use the selection state. It is kind of like an old library card catalog. You find what you want in the catalog and it then tells you what shelf to go look at to get the actual book.

 

6 hours ago, Samuel Derenboim said:

3. Does the application quit if and only if the object doesn't have a number?

My script above requires you to click on objects. The script exits when you click in a blank area of the drawing. There are lots of other ways to check for when to end.

6 hours ago, Samuel Derenboim said:

4. For some reason when running this script I still don't get a popup or dialog asking to enter the name of the object

I copied and pasted the script above into a blank document. I drew some rectangles and ran the script. When I clicked on the rectangles it named them with a sequential number. When I held down the Command key (Mac, probably Alt of Ctrl on Win), the dialog box to enter the name opened.

  • Like 2
Link to comment

@Pat Stanford thank you again for your consideration !

Let me clarify some of the questions you asked about in both posts

 

Quote

So are you going to manually attach the record to the objects you want and delete it from the objects you don't want?

The intention was to rewrite the information in the ID's if the amount of objects increased or decreased, so it would be easier to over-write or 'clear' the original contents of the ID field. This is why I thought the first process needs to 'clear' the ID Fields that way it 're'finds the closest object to the origin, and rewrites to all objects in the document. Looking at the code, the conditional statement  this would only be done if the fields were :

   IDcount:=1;
    B2:=False;
    While B2 = False do
        Begin
            TrackObjectN(0, CallBack, H1, X1,Y1);
            If H1 <> Nil then
                Begin
                    SetName(ID_Handle,Num2Str(0,IDcount));
                    IDcount:=IDcount+1;

 

Looked like it only did the operation if H1 was nil, so i figured by the same logic this script had to work in a similar way. If that was the case, the contents would be cleared, the conditional statement would 're' find all objects with records that have that handle set to nil and the apply the conditions of redoing the ID's for every object again. Sorry if It didn't make sense in my earlier post! Newbie here!

 

Quote

Your initial worksheet above shows not only a sequential number, but also some kind of code (ED, ND, NW). Do you need that? Or is that just stored separately and concattinated in the data tag?

The version that is displayed above is a combination of conditions that make each object unique. You're right in saying that these conditions vary based on

1. Direction (East, West, South, North)

2. Object Type (D=Door, W=Window, P=Partition / Wall, CW= Curtainwall

3. Every floor has a unique leading number. I.E. Cellar = 0, 1st Floor=1, 2nd Floor=2

4. Every Object ID Gets reset when it meets a different object, and object ID's have double digits for the purposes of quantity

i.e. = the 1st door on the North Face on the 2nd floor could be indicated as DN101

 

For the purposes of the questions I wanted to start simple - with only counting the objects. Since datatags and worksheets can concatenate information, I figured I wouldn't make the script too complicated. In this case, we can just simply do the ID's = which are dual decimal numbers, that way there can be more objects than 10 on a face per floor. All i need to do is reset count as soon as a different object is engage.

I.E. - Let's say I reach number 5 on walls, the count would be reset on a door which would be ND001 instead of ND006 (based on the original count). If it is too complex, we i can work with just a simple count for now.

 

Here is a breakdown of the worksheet. Note that i wasn't consistent in my use of the object type in my worksheet cells...I used W to represent walls until I ran into Windows, after which I used P to represent walls/partitions and W to represent windows. The error here is already mine!

 

image.png.195ff280c4081826ec7d94bc82c5efda.png

 

Quote

Do you really want/care about the order of the numbering? You specify that you want 1 to be the object closest to the origin, but what do you want after that? To "serial" out from the origin? Do you prefer 2D or 3D?

Generally The objects are in 3d like so :

image.png.b836633a670466d66fb20d2a5baa4e78.png

image.png.e18a280825a3a50449d10cb3fe66463b.png

 

But the Diagrams can be viewed in 2d and in 3d. It isn't really important how we get the Id's, so long as it starts counting from somewhere, and each ID is unique / sequential. It is for the plan examiner to cross reference the graphical drawing with the worksheet - for that particular object / condition.

 

Quote

Your sample worksheet shows the ID numbers with leading zeros, and different numbers of leading zeros. How do you want the decision on the number of IDs (and therefore the left zero padding) to be done?

 

Leading 0 is just the level. In reality the ID is just a 2 digit number

 

image.png.926ed3d13741656f6a56e77c46536e4f.png

 

Quote

I copied and pasted the script above into a blank document. I drew some rectangles and ran the script. When I clicked on the rectangles it named them with a sequential number. When I held down the Command key (Mac, probably Alt of Ctrl on Win), the dialog box to enter the name opened.

Oh wow, I didn't know ctrl activated the popup, Now that conditional statement is understandable!

 

Just to get on the same page :

 

If Command then N1:=IntDialog('Enter Number for this Object.', Num2Str(0,N1)); <= the command function activates the use of apple and CTRL for the keyboard, is this correct?

 

Question 2: what is the purpose of using the TrackObjectN Function?

TrackObjectN(0, CallBack, H1, X1,Y1,Z1);

***update*** - Is this function used to click on the object? (starting to get the feeling that's the click here operation)

 

Question 3: Why did you use a boolean condition here?

    B1, B2: Boolean;....and why are there two booleans? only one is being called out later on. maybe I don't see it, but is B1 Boolean inherently used somewhere to represent N1 in your script?

 

Quote

Begin
    N1:=1;
    B2:=False;
    While B2 = False do

 

Sorry for the long winded explanation! Grateful for your insight into the matter!!!!

Edited by Samuel Derenboim
Link to comment

Let's start with some basics.

 

Command is a Vectorworks function that tell you when the COMMAND key (Mac, I think CTRL on Windows) is being held down. It returns a boolean (true/false) value, True if the key is down, False if it is not down.

 

So. "If Command Then .... Else ...." translates to something like If the CTRL key is being held down then do what comes after the then otherwise do what comes after the Else. In my script it means only ask for a different number if the CTRL is held down.

 

TrackObject is a way to collect clicks on the drawing. It highlights ("pre-selection highlighting" the object you are having over and then when you click it returns a Handle that specifies the object you clicked on. In my script I wanted to be able to click on selected object and have them get a sequential number as their name.

 

If you really don't care where the numbering start on the drawing, then what you want to do becomes relatively simple. The following script will store the string S1 (defined as the letter D plus the number specified by N1) to every object that has a record with the name specified in the CONSTant REC into the field specified by the CONSTant Fld.

 

Procedure Execute is just a micro program that stores the value and increases value of counter N1. The Concat is necessary (even if you don't want the prefix) because only strings can be stored into records, numbers can't be, but the string equivalent can. [And yes, there are other ways to convert a number into a string.]

 

ForEachObject is the key to doing this easily. For Each object uses the criteria (in this case that the object has a specific record attached) and passes a handle for every object that meets that criteria to the Execute procedure, one object at a time. So Execute runs exactly once for each object that has the record attached.

 

Procedure NumberThem;

CONST	Rec='Your Record Name Here';
		Fld='Your Field Name Here';
		
VAR		H1:	Handle;
		N1:	Integer;
		S1: String;
		
Procedure Execute(Hd1:Handle);
	BEGIN
		S1:=Concat('D',N1);
		SetRField(Hd1, Rec, Fld, S1);
		N1:=N1+1;
	End;
	
BEGIN
	N1:=1;
	ForEachObject(Execute, ((R IN [Rec])));
End;

Run(NumberThem);

 

So that get's you the basics. To get more complicated and to generate all the other parts of your ID label, you just add more code to generate the proper string and then just concatenate them all together into a single string before the SetRField.

 

Caution: Pseudocode ahead:

 

If GetName(GetParametricRecord(Hd1))='Door' then S2:='D';

If GetName(GetParametricRecord(Hd1))='Window' then S2:='W';

 

If GetLName(Hd1)='Cellar' the S3:='0';

If GetLName(Hd1)='1st Flr.' then S3:='1';

S1:=Concat(S2, S3, N1);

 

HTH.  Come back with your next questions.

  • Like 1
Link to comment

@Pat Stanford Awesome! Thank you for the hint.

 

For some reason I thought the field needed to be an integer so I assigned it as such, and it kept getting an error, until i switched it to text - at which point it worked out beautifully.

 

Regarding the Pseudocode 🙂

 

The property that describes the object as 'window' 'door' 'curtainwall' 'wall' is located in another field called 'type'

My question:

 

How does GetName(GetParametricRecord(hd1) know to look into the record called 'type' in order to do : If GetName(GetParametricRecord(Hd1))='Door' then S2:='D';

Do i specify an additional constant for type?

 

******PROGRESS BELOW***********

 

Procedure NumberThem;

CONST    Rec='Test';
        Fld='ID';
        typ='Type';
                
VAR        H1:    Handle;
        N1:    Integer;
        S1,S2: String;

        
Procedure Execute(Hd1:Handle);
BEGIN
        
        S2:= GetRField(hd1,Rec,typ);
        If S2='Door' then S2:='D';
        If S2='Window' then S2:='W';
        If S2='Wall' then S2:='P';
        If S2='Curtainwall' then S2:='CW';

        S1:=Concat(S2,N1);
        SetRField(Hd1, Rec, Fld, S1);
        N1:=N1+1;
    End;

BEGIN
    N1:=1;
    ForEachObject(Execute, ((R IN [Rec])));
End;

Run(NumberThem);

Edited by Samuel Derenboim
Link to comment

update 2:

For some reason GetLName(HD1) not working - but the script compiles. My understanding is - it's supposed to get the layer name and then convert it to a string to See if it equates to S3 right? or does it need a separate handle?

 

Procedure NumberThem;

CONST

        Rec='Test';
        Fld='ID';
        typ='Type';
                
VAR 

       H1:    Handle;
        N1:    Integer;
        S1,S2,S3: String;

        
Procedure Execute(Hd1:Handle);

BEGIN
        
        S2:= GetRField(Hd1,Rec,typ);
        
        If S2='Door' then S2:='D';
        If S2='Window' then S2:='W';
        If S2='Wall' then S2:='P';
        If S2='Curtainwall' then S2:='CW';
        
        If GetLName(Hd1)='cellar' then S3:='0';
        If GetLName(Hd1)='1st floor' then S3:='1';

        S1:=Concat(S3,S2,N1);
        SetRField(Hd1, Rec, Fld, S1);
        N1:=N1+1;
    End;

BEGIN
    N1:=1;
    ForEachObject(Execute, ((R IN [Rec])));
End;

Run(NumberThem);

Link to comment

Update 3 :

 

Got Layers working. How do I add leading zeros?

 

Procedure NumberThem;

CONST    Rec='Test';
        Fld='ID';
        typ='Type';
                
VAR        H1, layhand: Handle;
        N1:    Integer;
        S1,S2,S3,layName: String;

        
Procedure Execute(Hd1:Handle);

BEGIN
        
        layhand:= GetLayer(hd1);
        layName := GetLName(layHand);
        S2:= GetRField(Hd1,Rec,typ);
                

        If layName='cellar' then S3:='0';
        If layName='1st floor' then S3:='1';
        
        If S2='Door' then S2:='D';
        If S2='Window' then S2:='W';
        If S2='Wall' then S2:='P';
        If S2='Curtainwall' then S2:='CW';
        
        S1:=Concat(S2,S3,N1);
        SetRField(Hd1, Rec, Fld, S1);
        N1:=N1+1;
    End;

BEGIN
    N1:=1;
    ForEachObject(Execute, ((R IN [Rec])));
End;

Run(NumberThem);

Link to comment

Update 4

All parameters functioning properly except 1 element -

 

How does one reset count when a condition ends?

 

I.E. If S3 changes then N1 = 1

 

Procedure NumberThem;

CONST    Rec='!CDA-EnergyTabular';
        Fld='ID_Count';
        typ='Obj.Type';
        dir='Orientation';
                
VAR        H1, layhand: Handle;
        N1,N2:    Integer;
        S1,S2,S3,S4,layName: String;

        
Procedure Execute(Hd1:Handle);

BEGIN
        
        layhand:= GetLayer(hd1);
        layName := GetLName(layHand);
        S2:= GetRField(Hd1,Rec,typ);
        S4:= GetRField(Hd1,Rec,dir);

        If layName='Cellar Areas' then S3:='0';
        If layName='1st Fl. Areas' then S3:='1';
        If layName='2nd Fl. Areas' then S3:='2';
        If layName='3rd Fl. Areas' then S3:='3';
        If layName='4th Fl. Areas' then S3:='4';
        If layName='5th Fl. Areas' then S3:='5';
        If layName='Roof Areas' then S3:='+';
                
        If S2='Door' then S2:='D';
        If S2='Window' then S2:='W';
        If S2=' Wall' then S2:='P';
        If S2='Cwall' then S2:='CW';
        If S2='Slab' then S2:='SL';
        If S2='Roof' then S2:='RF';
        
        If S4= 'East' then S4:='E';
        If S4= 'West' then S4:='W';
        If S4= 'North' then S4:='N';
        If S4= 'South' then S4:='S';
        If S4= 'Horizontal' then S4:='H';
        
        S1:=Concat(S4,S2,S3,N1);
        SetRField(Hd1, Rec, Fld, S1);
        N1:=N1+1;
    End;

BEGIN
    N1:=1;
    ForEachObject(Execute, ((R IN [Rec])));
End;

Run(NumberThem);

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...