Introduction to the ZW3D API ___________________________________________________________________________ The ZW3D API is a basic set of C functions for implementing custom commands and operations in ZW3D. The ZW3D API is used to create DLL's that are dynamically loaded by ZW3D at runtime. Functions in a ZW3D API DLL may be invoked from the ZW3D user interface directly or through a user-defined command template. Simple examples of both are given in this document. A command template is an ascii-encoded set of instructions that tells the ZW3D Input Manager what type of input data (e.g. point selections, entity picks) to gather from the user. When the user has finished entering the data specified by the template, the ZW3D Input Manager automatically sends the data to the C function associated with the template. A command template is defined in a text file with a ".t" extension. The file is dynamically compiled and loaded into memory using the ZW3D API function named cvxCmdTemplate(TemplateFileName). A group of templates can be pre-compiled into a single binary ZW3D file, which may be registered with ZW3D in your custom library's initialization function (see cvxFormsPrecompiled()). A command template may be defined and registered with ZW3D on-the-fly using cvxTplInit() and related "cvxTpl..." functions. Applications programmed through the ZW3D API can also gather data through GUI forms that are defined similarly to command templates. GUI forms have more sophisticated GUI options than command templates, but they have less built in "intelligence". A GUI form is composed of widgets of different types. A template defines what widgets are used to compose a form, their relative positioning on the form, and various options that control the widget's appearance and behavior. GUI forms are displayed, queried, and undisplayed using the "cvxForm..." functions defined in the ZW3D API. See the "Command Templates" and "GUI Forms" sections for more information. "Hello World" Example ___________________________________________________________________________ The following example shows how to create a ZW3D API DLL with a function that prints "Hello World" in the ZW3D message area. 1) Copy zw3dmain.lib from the "api" sub-folder of the ZW3D installation folder a local folder (i.e. "MyFolder"). The path of the installation folder is listed under the "About..." option on the ZW3D "Help" pulldown menu. 2) Copy VxApi.h from the "api" folder to "MyFolder". 3) Create a simple text file named MyLib.c in "MyFolder" using Notepad or a similar text editor. Type the following code in the file. You may ignore the comments, which are included here for your instruction. #include "VxApi.h" void MyFunction(void); /* ** You must supply an initialization function whose name ** is the name of your DLL suffixed with "Init" (MyLibInit). ** ** This function is automatically called by ZW3D when it ** loads your DLL at startup. ** ** It should perform whatever initializations your DLL ** requires, such as registering your callback functions. ** ** The function must be declared with the arguments shown. ** ** The function should return 0 if it is successful; 1 if it fails. */ int MyLibInit(int format, void *data) { /* register your function with ZW3D */ cvxCmdFunc("MyFunction",(void*)MyFunction,VX_CODE_GENERAL); return(0); } /* ** You must also supply an exit (i.e. cleanup) function whose ** name is the name of your DLL suffixed with "Exit" (MyLibExit). ** ** This function is automatically called by ZW3D during its ** shutdown (i.e. exit) process. ** ** It should perform whatever cleanup your DLL requires ** before ZW3D is shutdown. ** ** This function should always return 0. */ int MyLibExit(void) { /* put your cleanup code here */ return(0); } /* ** This is the function registered in MyLibInit(). */ void MyFunction(void) { cvxMsgDisp("Hello world!"); } 4) Create another text file named "MyLib.def" in "MyFolder". This file must specify all functions "exported" by your library. Type the following text in it. LIBRARY MyLib.dll EXPORTS MyLibInit MyLibExit MyFunction 5) Build MyLib.dll using the following commands: cl.exe /nologo /c /D WIN32 /MT /LD /Z7 MyLib.c link /DEF:MyLib.def /DLL /OUT:MyLib.dll *.obj zw3dmain.lib 6) Copy MyLib.dll from "MyFolder" to a sub-folder named "apilibs" in your ZW3D user folder or main ZW3D program folder. The paths to these folders are shown at the bottom of the first tab of the ZW3D Configuration menu (see Utilities/Configuration... or Help/About...). 7) Start ZW3D. It will automatically load DLL's found in an "apilibs" folder. 8) Type "~MyFunction" at the ZW3D command line. ZW3D invokes MyFunction(), which prints "Hello World" in the ZW3D message area. This command string (~MyFunction) can be assigned to an icon or button on a custom toolbar. An example showing how to register a custom toolbar with ZW3D is given later in this section. Custom History Operation Example ___________________________________________________________________________ The following example shows how to create a DLL that implements a custom hole operation logged to the active part history. It assumes you've already copied zw3dmain.lib and VxApi.h to "MyFolder" (see the "Hello World" example). 1) Create a simple text file named MyLib.c in "MyFolder" using Notepad or a similar text editor. Type the following code in the file. You may ignore the comments, which are included here for your instruction. #include "VxApi.h" #include "stdio.h" int MyCommand(int idData); /* ** Library initialization function. */ int MyLibInit(int format, void *data) { /* register callback function */ cvxCmdFunc("MyCommand",(void*)MyCommand,0.0); /* register custom command template */ cvxTplInit(VX_HIST_SOLID_EDIT,"MyCommand","Insert hole"); cvxTplInit2("MyCommand",NULL,NULL,0); cvxTplInit3(0,0,1); cvxTplPntAdd(1,0,"Point","Select hole insertion point",0); cvxTplPntOpt(1,VX_INP_PNT_ON_ANY_FACE,NULL,0); cvxTplRegister(); return(0); } /* ** Exit (i.e. cleanup) function. */ int MyLibExit(void) { return(0); } /* ** This is the function registered in MyLibInit(). */ int MyCommand ( int idData /* I: command input data */ ) /* DESCRIPTION: Main callback function for MyCommand.t. Returns 1 if error; 0 if successful. */ { svxData Point; svxHoleData Hole; cvxDataGet(idData,1,&Point); cvxMemZero((void*)&Hole,sizeof(Hole)); Hole.Type = VX_HOLE_COUNTER_BORE; Hole.idInsFace = Point.idEntity; Hole.Count = 1; Hole.Points = &Point.Pnt; Hole.Diameter1 = 15.0; Hole.Diameter2 = 25.0; Hole.Depth1 = 30.0; Hole.Depth2 = 7.0; if (cvxPartHole(&Hole,NULL)) return(1); return(0); } 2) Create another text file named "MyLib.def" in "MyFolder". This file must specify all functions "exported" by your library. Type the following text in it. LIBRARY MyLib.dll EXPORTS MyLibInit MyLibExit MyCommand 3) Build MyLib.dll using the following commands: cl.exe /nologo /c /D WIN32 /MT /LD /Z7 MyLib.c link /DEF:MyLib.def /DLL /OUT:MyLib.dll *.obj zw3dmain.lib 4) Copy MyLib.dll from "MyFolder" to a sub-folder named "apilibs" in your ZW3D user folder or main ZW3D program folder. The paths to these folders are shown at the bottom of the first tab of the ZW3D Configuration menu (see Utilities/Configuration... or Help/About...). 5) Start ZW3D. It will automatically load DLL's found in an "apilibs" folder. 6) Type "!MyCommand" at the ZW3D command line. ZW3D gathers input data specified by the "MyCommand" template and passes it to MyCommand(). ZW3D automatically logs an operation to the history that calls MyCommand() when it is regenerated. The command string (!MyCommand) can be assigned to an icon or button on a custom toolbar. An example showing how to register a custom toolbar with ZW3D is given later in this section. Custom Feature Command Templates ___________________________________________________________________________ As mentioned at the beginning of this document, a custom command template may be defined in an ascii template file (*.t) that is registered in the "Init" function of your custom library using cvxCmdTemplate(). A command template that prompts for a series of points and then calls a C API function named MyLines() looks like the following: # comments are preceded by a pound sign TEMPLATE=MyLines description=Create line segments connecting points. function=CustomOp custom=MyLines.c no_repeat FIELD=Points class=point id=1 prompt=Select points to connect. list options=/face/edge/curve/point/, trigger Put this template definition in an ascii text file (i.e. MyLines.t). The file can include comments, which are identified by a leading pound sign (#). Load the template file in your DLL's "Init" funtion using cvxCmdTemplate(). In order for cvxCmdTemplate() to find the template file, you must first register the path to the template file's folder using cvxPathAdd(). Generally, the template file should be installed in a sub-folder of the "apilibs" folder where your DLL is installed. Use cvxPathApiLib() to get the path to the "apilibs" folder where your DLL is installed). Note that the "function" keyword in the "MyLines" template is always followed by the "CustomOp" keyword to tell ZW3D that the template defines a custom history operation. When you invoke the "!MyLines" command, ZW3D prompts for the specified inputs (e.g. point picks). The inputs are placed in a data container and the id of the container is passed to the function specified after the "custom" keyword (i.e. "custom=MyLines.c). "custom=MyLines.c" tells ZW3D to look up the MyLines() function pointer registered with cvxCmdFunc() in your library's "Init" function. The id of the input data container associated with the MyLines command is passed to the MyLines() function. When MyLines() returns, the data container is automatically deleted and the ZW3D display is completely redrawn to make sure it is synchronized with the database. Use "custom=MyLines.ci" instead of "custom=MyLines.c" to force ZW3D to incrementally display modifications to graphic entities. For simple commands, this can be a faster way to update the display, but it should only be used with wireframe style operations. It should not be used with custom commands that edit surfaces or solids (i.e. shapes/faces/edges). The following code registers the MyLines command template in the initialization function of MyLib.dll. It assumes the template file resides in the "apilibs" folder. int MyLibInit(int format, void *data) { vxPath ApiPath; /* register your function with ZW3D */ cvxCmdFunc("MyLines",(void*)MyLines,VX_CODE_GENERAL); /* register command template file */ cvxPathApiLib("MyLib", ApiPath); cvxPathAdd(ApiPath); cvxCmdTemplate("MyLines.t"); return(0); } The following is sample code for a MyLines() function using the API: /* ** This function uses point input stored in the data container ** referenced by "idData" to create line segments connecting ** the points. It returns 1 if error; 0 if successful. */ int MyLines (int idData) { int i, Count=0; svxData *List=NULL; char buf[128]; /* get list of point inputs */ if (cvxDataGetList(idData,1,&Count,&List)) return(1); /* return error if less than two points were entered */ if (Count { 2) { cvxMsgDisp("Enter at least two points."); cvxMemFree((void**)&List); return(1); } /* create line segments connecting the input points */ for (i=0; i { (Count-1); i++) { if (cvxPartLine2pt(&List[i].Pnt, &List[i+1].Pnt, NULL)) { cvxMemFree((void**)&List); return(1); } } VxMemFree((void**)&List); return(0); } Dynamic Echo for a Custom Command ___________________________________________________________________________ The following code implements a command that changes "Diameter" and "Depth" variables of the active part, dynamically updating the part each time the "Diameter" and "Depth" inputs are changed. When the user presses "Okay" or "Cancel", the part is automatically rolled back to its original state. Then, if the user pressed "Okay", the evaluation function associated with the command is called. The main point is that preview data created during command input is automatically undone. This prevents the preview from tying up a lot of memory with undo-redo data. The key to undo-redo cleanup are the calls to cvxUndoRedoMarker() and cvxCmdMarker() in TestCmdInit(). They put a marker in the undo-redo history and register it with the active command. When the command is okay'd or cancelled, all operations after the marker are automatically undone. #include "VxApi.h" #include {stdlib.h} #include {stdio.h} #include {string.h} int TestCmd(int idData); void TestCmdInit(int idData); int TestCmdCb(char*,int,int); /* ** Library initialization function. */ int MyLibInit(void) { /* register functions */ cvxCmdFunc("TestCmd",(void*)TestCmd,0.0); cvxCmdCallback("TestCmdCb",(void*)TestCmdCb); cvxCmdCallback("TestCmdInit",(void*)TestCmdInit); cvxTplInit(VX_STANDARD_COMMAND,"TestCmd","Modify Diameter and Depth"); cvxTplInit2("TestCmd","TestCmdInit",NULL,0); cvxTplInit3(0,0,1); cvxTplNumAdd(1,0,"Diameter","Enter diameter",VX_INP_DISTANCE); cvxTplNumOpt2(1,"TestCmdCb",0,0); cvxTplNumAdd(2,0,"Depth","Enter depth",VX_INP_DISTANCE); cvxTplNumOpt2(2,"TestCmdCb",0,0); cvxTplNumAdd(3,0,"Distance","Enter distance",VX_INP_DISTANCE); cvxTplNumOpt2(3,"TestCmdCb",0,0); cvxTplRegister(); return(0); } /* ** This is the function that is called after the "TestCmd" ** template is finished gather using input. It should ** return 0 if it executes successfully; 1 if there is an error. ** A pointer to this function is registered in MyLibInit(). */ int TestCmd ( int idData /* I: command input data */ ) { svxData Diameter, Depth; svxVariable Variable[2]; cvxDataGet(idData,1,&Diameter); cvxDataGet(idData,2,&Depth); cvxMemZero((void*)Variable,2*sizeof(svxVariable)); strcpy(Variable[0].Name,"Diameter"); Variable[0].Value = Diameter.Num; Variable[0].isDistance = 1; strcpy(Variable[1].Name,"Depth"); Variable[1].Value = Depth.Num; Variable[1].isDistance = 1; cvxPartVarSet(2, Variable, 0); return(0); } /* ** Initialization callback function invoked before ** the "TestCmd" template starts gathering user input. ** A pointer to this function is registered in MyLibInit(). */ void TestCmdInit ( int idData /* I: command input data */ ) /* DESCRIPTION: Callback function invoked when a command template is initialized. */ { svxVariable Variable; svxData Data; vxName Marker; cvxMemZero((void*)&Variable,sizeof(Variable)); cvxMemZero((void*)&Data,sizeof(Data)); Data.isNumber=1; strcpy(Variable.Name,"Diameter"); if (!cvxPartVarGet(&Variable)) { Data.Num = Variable.Value; cvxDataSet(idData,1,&Data); } strcpy(Variable.Name,"Depth"); if (!cvxPartVarGet(&Variable)) { Data.Num = Variable.Value; cvxDataSet(idData,2,&Data); } /* make start of this command in undo-redo history */ cvxUndoRedoMarker(Marker); cvxCmdMarker(Marker,Marker); return; } /* ** Callback function invoked each time user input ** for "TestCmd" is modified. A pointer to this ** function is registered in MyLibInit(). */ int TestCmdCb(char*Form,int idField,int idData) { return(TestCmd(idData)); } Adding a User Toolbar to ZW3D ___________________________________________________________________________ Typically you would tie your custom API-based functions or commands to a custom toolbar that shows up on the "User" pulldown menu. A custom toolbar is defined in an ascii template file (.t) that is dropped into the "supp" folder of the runtime ZW3D user folder. Any icons (.bmp) used on the custom toolbar should be located in the same folder. The format of a toolbar menu template is shown below. This example uses both text buttons (label=XXXX) and pre-compiled ZW3D icons (icon = *.xpm). The "target" keyword is followed by a number that indicates which ZW3D edit mode the toolbar should be associated with (2=part, 3=sketcher, 4=sheet, 5=drawing, 6=cam plan). In the following case, the toolbar is for use in "part" edit mode (i.e. target=2). Note that the name of the template file must be the same as the menu name. That is, you would put the following menu in a file named "MyUserMenu.t" in the "supp" sub-folder of the ZW3D user folder. # target=2 ########################################### MENU=MyUserMenu class=user lock ITEM=button label=Hello command=~MyFunction hint=Execute custom "Hello World" function. ITEM=button label=Hole command=!MyCommand hint=Execute custom "Insert Hole" command. ITEM=opt_btn menu=MySubMenu ########################################### # sub-menu MENU=MySubMenu class=options persist ITEM=button icon=ICON022.xpm command=!FtFlltConst hint=Fillet a solid. ITEM=button icon=ICON023.xpm command=!FtChamConst hint=Chamfer a solid. ITEM=button icon=ICON024.xpm command=!FtShell hint=Shell a solid.