Jump to content
Developer Wiki and Function Reference Links Read more... ×
AEChadwick

Auto-Numbering Procedure for use in PIO (my latest kludge)

Recommended Posts

Hello friends

 

I have long desired an extensible way to add automatic ID numbers to my custom PIOs, and finally took a day to cobble one together. I am submitting it here for perusal, please offer suggestions. (caveat: I know am a hack coder, please don’t be unkind.) (also, i try to name variables knowing that my future self will never remember what “wBpstXX” was ever supposed to mean.)

 

I wanted a system that would simply start from 1 and count up, nominatively to the number of [same objects]. I wanted it to store each number so existing objects would not change their identification--but I wanted the system to fill in available numbers, like if an object got deleted the next object would re-use the available number.

 

This example is built off a rectangle object, purely for demonstration; in addition to LineLength and BoxWidth, the script expects a parameter called __SpecialID of type Text. This is purely to store the ID (the preceding underscore makes the parameter invisible to the user). This script will draw a box and slug the number inside. (the copy-or-new routine is simply the code example from isNewCustomObject)

 

Some nice improvements will be an optional prefix or suffix parameter, allowing things like “W11” or “18xSF" for unique reference; and maybe the ability to add trailing or leading numbers, so “4” automatically becomes “04.” But those can all follow once the basic functionality is foolproof.

 

See what you think.

 

—AE

 

PROCEDURE Plugin;

VAR
    x, y, w, h : REAL;
    boxLeft, boxBottom, boxRight, boxTop : REAL;
    pioHandle,rh,wh : HANDLE;
    result, IsThisCopy, WeGotOne : BOOLEAN;
    NumberOfPIOs : LONGINT;
    pioName, thisTypeOfPIO : STRING;
    MySpecialID, theUniqueID : STRING;
    theNumber : LONGINT;
    TheStringWeBeChecking, theStringWeNeed : STRING;

PROCEDURE GoThroughEveryPIO(EachPIO : Handle);
begin
    theStringWeNeed := GetRField(EachPIO, thisTypeOfPIO, '__SpecialID');
    if theStringWeNeed = TheStringWeBeChecking then WeGotOne := FALSE;
end;

PROCEDURE GenerateUniqueID;
Begin
    theNumber := 1;
    repeat
        WeGotOne := TRUE;
        TheStringWeBeChecking := Num2Str(0, theNumber);
        ForEachObject(GoThroughEveryPIO, PON=thisTypeOfPIO);
        if theNumber = NumberOfPIOs then WeGotOne := TRUE else theNumber := theNumber+1;
        until WeGotOne = TRUE;
    theUniqueID := TheStringWeBeChecking;
    IF IsNewCustomObject(pioName) THEN begin
        MySpecialID := theUniqueID;
        SetRField(pioHandle, pioName, '__SpecialID', MySpecialID);
        SetName(pioHandle, MySpecialID);
    end;
    IsThisCopy := MySpecialID <> GetName(pioHandle); 
    IF IsThisCopy THEN begin
        MySpecialID := theUniqueID;
        SetRField(pioHandle, pioName, '__SpecialID', MySpecialID);
        SetName(pioHandle, MySpecialID);
    end;
End;

BEGIN
result:= GetCustomObjectInfo(pioName,pioHandle,rh,wh);
thisTypeOfPIO := (GetObjectVariableString(pioHandle,1166));
NumberOfPIOs := Count(PON=thisTypeOfPIO);

MySpecialID := p__SpecialID;

GenerateUniqueID;

boxLeft:=0; boxBottom:=-(PBOXWIDTH/2); boxRight:=PLINELENGTH; boxTop:=(PBOXWIDTH/2);
Rect(boxLeft,boxBottom,boxRight,boxTop);
            
TextOrigin((PLINELENGTH/2),0);
TextSize(12);
CreateText(Concat(MySpecialID, ' of ', NumberOfPIOs));
END;

RUN(Plugin);

 

 

 

Edited by AEChadwick
cleaned up some vestigial bad math so people wouldn't get distracted by my poor coding.

Share this post


Link to post

Hi AE,

 

I created a script to do this, using the Pos and Copy functions with these variables: 

pioName,letters,letter,remainl,nextl, new: STRING; loc: INTEGER; and based on the code below and by running the 'nextLetter' from your main program block. It works very robustly but it did take a bit of fiddling around with to set it up.... What it won't do is allow you to enter your own letter / label to the new item. 

 

PROCEDURE removeLetter (h2: HANDLE);
BEGIN
    pioName:=GetPioName(h2);  
    letter:= GetRField(h2,pioName,'Ref');
    loc:=Pos(letter,remainl);
    IF loc <> 0 THEN BEGIN    
        Delete(remainl,loc,1);
        END; 
END;


PROCEDURE nextLetter;
BEGIN
    letters:= 'abcdefghijklmnopqrstuvwxyz';

    remainl:= Copy(letters,1,26);
    ForEachObject(removeLetter,((C='XXX') AND (T=86) AND (V=TRUE)));
    IF COUNT ((C='XXX') AND (T=86) AND (V=TRUE)) = 0 THEN BEGIN
        nextl:='a';
        END ELSE BEGIN
        nextl:= Copy(remainl,1,1); 
        END;
END;

 

It is not very obvious but I hope this could be helpful to you and good luck!

MT

Share this post


Link to post

Glad you like it - I forget how I arrived at it but is great to find ways to achieve goals that, sometimes, seem unachievable. Let me know if you need any help with it but I think you should have enough info to get it working the way you want it to.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

 

7150 Riverwood Drive, Columbia, Maryland 21046, USA   |   Contact Us:   410-290-5114

 

© 2018 Vectorworks, Inc. All Rights Reserved. Vectorworks, Inc. is part of the Nemetschek Group.

×