Some example source code is shown here, the collaborative code is
highlighted in blue and the comments are in green.
The modules shown here are MShareLat, a completely new module, and
MShareGraph3D which is based on the Graph3D module but allows for
collaborative work. The lines of
code of MShareGraph3D shown in black are the original module code of
Graph3D. This demonstrates how
little additional code was required to convert it to be a collaborative module.
// Collab Includes #include <cx/cxCollab.h> // Explorer Includes #include <cx/Typedefs.h> #include <cx/Info.h> #include <cx/cxLattice.api.h> #include <cx/DataAccess.h> #include <cx/PortAccess.h> #ifdef __cplusplus extern "C" { #endif /* * User Function */ void ShareLat(long pass,cxLattice **OutLat) { static cxCollab collab_info;//Create a static instance of the collaboration //class so that connection state and other info isn't //lost between each invocation of this function. static int firsttime = 1; if (firsttime == 1) { firsttime = 0; //Register a single collaborative port: name, source type, datatype collab_info.portRegister("In_Lat",INPUT,LATTICE); return; } // Check reserved widgets looking for connect/disconnect instructions collab_info.checkWidgets(); // If connected then can do things if (collab_info.isConnected()) { // Check for data to read if (collab_info.newData("In_Lat")) { *OutLat = collab_info.getLattice("In_Lat"); cxDataRefInc((void *)*OutLat); } } // Do stuff in here if need to, sing, dance etc . . . // If connected then can do things if (collab_info.isConnected()) { // Check for data to send int port = cxInputPortOpen("In_Lat"); if (cxInputDataChanged(port)) collab_info.sendData("In_Lat"); } if ((pass) && (cxInputDataChanged(cxInputPortOpen("In_Lat")))) { *OutLat = (cxLattice *)cxInputDataGet( cxInputPortOpen("In_Lat")); } } // end User function #ifdef __cplusplus } #endif ==============================================================================MShareGraph3D
// Collab Includes #include <cx/cxCollab.h> /* Inventor Includes */ #include <Inventor/nodes/SoGroup.h> #include <Inventor/nodes/SoMaterial.h> #include <Inventor/nodes/SoTransform.h> #include <Inventor/nodes/SoCube.h> #include <Inventor/fields/SoSFVec3f.h> #include <Inventor/nodes/SoComplexity.h> #include <Inventor/nodes/SoShapeHints.h> /* Explorer Includes */ #ifdef WIN32 #include <float.h> #else #include <values.h> #endif #include <cx/DataAccess.h> #include <cx/DataTypes.h> #include <cx/Geometry.h> #include <cx/Lookup.h> #include <cx/PortAccess.h> #include <cx/UI.h> // A convenient way to list all of the ports that we are going // to register for collaboration, along with their port types and data types char *port_names[] = {"Graph Type","Color By What","Height Scale", "Surface Scale","Treat Negatives As ?"}; int port_dataTypes[] = {PARAMETER,PARAMETER,PARAMETER,PARAMETER,PARAMETER}; int port_types[] = {INPUT,INPUT,INPUT,INPUT,INPUT}; int num_ports = 5; #ifdef __STDC__ extern "C" void graph3d(cxGeometry **geom) #else extern "C" void graph3d(geom) cxGeometry **geom; #endif { static cxCollab collab_info; // class instance for collaborative elements static int firsttime = 1; cxCoord *coord; cxCoordType coordtype; cxData *data_struct; cxErrorCode err; cxLookup *clut; cxPrimType primType; double smin, smax; float color_array[4], color_value, *coordvals, cyl_point[6], *data, delx, dely, dx, dy, max_val, min_val, point[3], radius, scalefactor, size, s_min = 0.01, s_max = 1.0, xmin, ymin; int port; long *dims, flag, i, j, nDataVar, nDim; int cmap_flag; int ngtve; double val; // Ports handled internally cxLattice *lat, *cmap; long color_by_what, graph_type, n_vals; double h_scale, s_scale; cxParameter *Scale_Param; lat = (cxLattice *)cxInputDataGet(cxInputPortOpen("Data In")); cmap = (cxLattice *)cxInputDataGet(cxInputPortOpen("ColorMap")); // Check to see if we are connected. If we are then check to see if any // new data has arrived on any of the ports that we registered as being // collaborative. If we find new data (or the "sync values" button has // been pressed) compile a list of port names for which data should be // sent. Then send the data. if (collab_info.isConnected()) { char **portNames = new char * [num_ports]; int port,numPorts=0; int sendAll = FALSE; port = cxInputPortOpen("Sync Values"); if (cxInputDataChanged(port)) sendAll = TRUE; // Compile list of port names for which data is new for (int i = 0; i < num_ports; i++ ) { port = cxInputPortOpen(port_names[i]); if ((cxInputDataChanged(port)) || (sendAll)) { int len = strlen(port_names[i])+1; portNames[numPorts] = new char [len]; bzero(portNames[numPorts],len); strcpy(portNames[numPorts],port_names[i]); numPorts++; } } // If some new data, then send to collaborators if (numPorts > 0) collab_info.sendData(numPorts,portNames); //collab_info.sendData(portNames[0]); // Tidy Up for (i = 0; i < numPorts; i++ ) free(portNames[i]); free(portNames); // If we were just sync(ing) values, then stop having sent the // data values. if (sendAll) return; } long dummy = cxParamLongGet((cxParameter*)cxInputDataGet( cxInputPortOpen("Sync Values"))); graph_type = cxParamLongGet((cxParameter*)cxInputDataGet( cxInputPortOpen("Graph Type"))); color_by_what = cxParamLongGet((cxParameter*)cxInputDataGet( cxInputPortOpen("Color By What"))); n_vals = cxParamLongGet((cxParameter*)cxInputDataGet( cxInputPortOpen("Treat Negatives As ?"))); h_scale = cxParamDblGet((cxParameter*)cxInputDataGet( cxInputPortOpen("Height Scale"))); s_scale = cxParamDblGet((cxParameter*)cxInputDataGet( cxInputPortOpen("Surface Scale"))); if (firsttime == 1) { firsttime = 0; // Register (once only) the names of ports that we want to be // collaborative collab_info.portRegister(num_ports,port_names, port_types,port_dataTypes); // consume this value long dummy = cxParamLongGet((cxParameter*)cxInputDataGet( cxInputPortOpen("Sync Values"))); return; } // Check reserved widgets looking for connect/disconnect/re-connect // instruction collab_info.checkWidgets(); // If connected then can do things if (collab_info.isConnected()) { // Turn on Sync Values button cxInWdgtShow("Sync Values"); // Check for data to be read from the collaborative session // associated with port names that we have registered. // Update the control panel if new data is found. if (collab_info.newData("Graph Type")) { graph_type = cxParamLongGet(collab_info.getParameter("Graph Type")); cxInWdgtLongSet("Graph Type",graph_type); } if (collab_info.newData("Color By What")) { color_by_what = cxParamLongGet( collab_info.getParameter("Color By What")); cxInWdgtLongSet("Color By What",color_by_what); } if (collab_info.newData("Treat Negatives As ?")) { n_vals = cxParamLongGet( collab_info.getParameter("Treat Negatives As ?")); cxInWdgtLongSet("Treat Negatives As ?",n_vals); } if (collab_info.newData("Height Scale")) { h_scale = cxParamDblGet(collab_info.getParameter("Height Scale")); cxInWdgtDblSet("Height Scale",h_scale); } if (collab_info.newData("Surface Scale")) { s_scale = cxParamDblGet(collab_info.getParameter("Surface Scale")); cxInWdgtDblSet("Surface Scale",s_scale); } } // If no data then finish if (lat == NULL) return; /* Get the input lattice and determine its data type */ err = cxLatDescGet(lat, &nDim, &dims, NULL, &nDataVar, &primType, NULL, NULL, &coordtype); if (err == cx_err_error) { cxModAlert("No memory to get lattice description, return control"); return; } /* Get the data structure and data */ cxLatPtrGet(lat, &data_struct, (void **) (&data), &coord, (void **) (&coordvals)); if (err == cx_err_error) { cxModAlert("Invalid lattice pointer used, return control"); return; } /* Get the maximum size of the ground area for the blocks * This code assumes that a uniform lattice is connected */ if (coordtype != cx_coord_uniform) { cxModAlert("Unexpected lattice type connected, return control"); return; } delx = (coordvals[1] - coordvals[0])/((float) dims[0] - 1.0); dely = (coordvals[3] - coordvals[2])/((float) dims[1] - 1.0); dx = 0.5 * delx; dy = 0.5 * dely; xmin = coordvals[0]; ymin = coordvals[2]; /* If a colour map is attached, generate its lookup table */ if (cmap != NULL) { clut = cxLookupCreate(cmap, cx_lookup_nearest); cmap_flag = 1; } else cmap_flag = 0; /* Find minimum and maximum values in input lattice */ #ifdef WIN32 min_val = FLT_MAX; max_val = FLT_MIN; #else min_val = MAXFLOAT; max_val = MINFLOAT; #endif for (j = 0; j < dims[1]; j++) { for (i = 0; i < dims[0]; i++) { val = extract_value(data, primType, (j*dims[0]+i)); if (min_val > val) min_val = val; if (max_val < val) max_val = val; } } /* Scale the height according to the minimum and maximum values * allowing for a user-specified multiplication factor h_scale */ if (max_val == min_val) scalefactor = 0.08 * (float) h_scale; else scalefactor = 8.0 * (float) h_scale / (max_val - min_val); /* Set external Scale Factor */ Scale_Param = cxParamDoubleNew((double)scalefactor); cxOutputDataSet(cxOutputPortOpen("Scale"),(void *)Scale_Param); /* Initialise the geometry structure */ *geom = cxGeoNew(); cxGeoBufferSelect(*geom); /* New code to use shared memory geometry transcription */ port = cxOutputPortOpen("Geometry"); cxGeoBufferPortSet(port); /* Create the geometry */ cxGeoRoot(); cxGeoDelete(); /* If a colour map is attached get a colour value * else use a fixed value 0f 0.8 */ if (!cmap_flag) { color_array[0] = 0.8; color_array[1] = 0.8; color_array[2] = 0.8; } /* The distance between blocks is determined by the * user-specified scale factor s_scale */ if (s_scale < s_min) { /* If the size would be too small then it is clamped * and the widget must be examined for correct values * before setting it to the clamped value */ size = s_min; cxInWdgtMinMaxGet("Surface Scale", &smin, &smax); flag = 0; if (smin > size) { smin = (double) size; flag = 1; } if (smax < smin) { smax = smin; flag = 1; } if (flag == 1) cxInWdgtDblMinMaxSet("Surface Scale", smin, smax); cxInWdgtDblSet("Surface Scale", (double) size); } else if (s_scale > s_max) { /* If the size would exceed the available space then it is * clamped and the widget must be examined for correct * values before setting it to the clamped value */ size = s_max; cxInWdgtMinMaxGet("Surface Scale", &smin, &smax); flag = 0; if (smin > size) { smin = (double) size; flag = 1; } if (smax < smin) { smax = smin; flag = 1; } if (flag == 1) cxInWdgtDblMinMaxSet("Surface Scale", smin, smax); cxInWdgtDblSet("Surface Scale", (double) size); } else size = (float) s_scale; /* Build up the geometry by inspecting each node */ for (j = 0; j < dims[1]; j++) { for (i = 0; i < dims[0]; i++) { val = extract_value(data, primType,(j*dims[0]+i)); /* The colour used for the node */ if (cmap_flag) { switch (color_by_what) { case 0: color_value = (float) i / (float) (dims[0]-1); break; case 1: color_value = (float) j / (float) (dims[1]-1); break; case 2: color_value = (float) val; cxLookupInterp(clut, &color_value, (void *)color_array); break; } cxLookupInterp(clut, &color_value, (void *)color_array); } /* See if negative */ if (val < 0.0) ngtve = 1; /*True*/ else ngtve = 0; /* False */ /* Make Positive */ if ((n_vals == 1) && (ngtve)) { val = -1 * val; ngtve = 0; /* False */ } /* Select the type of graph */ switch (graph_type) { case 0: /* Blocks */ if ((n_vals != 2) || (!ngtve)) { /* Create a group */ SoGroup *Group = new SoGroup ; Group->ref(); /* Add Color */ SoMaterial *mtl = new SoMaterial; Group->addChild(mtl); mtl->diffuseColor.setValue(color_array[0],color_array[1], color_array[2]); /* Create Transform */ SoTransform *Trans = new SoTransform; Group->addChild(Trans); point[0] = (float) xmin + i * delx ; point[1] = (float) ymin + j * dely ; point[2] = (float) (scalefactor * val)/2 ; Trans->translation.setValue(point); SoComplexity *complex = new SoComplexity; Group->addChild(complex); complex->value.setValue(0.2); /* Create cube */ point[0] = (float) (xmin + i * delx + dx * size) - (xmin + i * delx - dx * size); point[1] = (float) (ymin + j * dely + dy * size) - (ymin + j * dely - dy * size); if (ngtve) point[2] = (float) scalefactor * val * -1; else point[2] = (float) scalefactor * val ; SoCube *cube = new SoCube; Group->addChild((SoNode *)cube); cube->width.setValue(point[0]); cube->height.setValue(point[1]); cube->depth.setValue(point[2]); /* Add to Explorer Geom */ cxGeoInventorDefine(Group); Group->unref(); } break; case 1: /* Cylinders */ /* A cylinder is defined by 2 centres and a radius * A cone is defined by a centre, a top and a base radius */ if ((n_vals != 2) || (!ngtve)) { cyl_point[0] = cyl_point[3] = xmin + i * delx; cyl_point[1] = cyl_point[4] = ymin + j * dely; cyl_point[2] = 0.0; cyl_point[5] = scalefactor * val; if (dx < dy) radius = dx * size; else radius = dy * size; cxGeoCylindersDefine(1, &cyl_point[0], &cyl_point[3], &radius); cxGeoComplexityAdd(0.2); cxGeoColorAdd(1, color_array, CX_GEO_PER_OBJECT); } break; case 2: /* Cones */ /* A cylinder is defined by 2 centres and a radius * A cone is defined by a centre, a top and a base radius */ if ((n_vals != 2) || (!ngtve)) { cyl_point[0] = cyl_point[3] = xmin + i * delx; cyl_point[1] = cyl_point[4] = ymin + j * dely; cyl_point[2] = 0.0; cyl_point[5] = scalefactor * val; if (dx < dy) radius = dx * size; else radius = dy * size; cxGeoConesDefine(1, &cyl_point[0], &cyl_point[3], &radius); cxGeoComplexityAdd(0.2); cxGeoColorAdd(1, color_array, CX_GEO_PER_OBJECT); } break; default: /* Unexpected type */ cxModAlert ("unexpected graph type requested, return control"); return; } } } if (cmap_flag) { cxLookupDestroy(clut); } cxGeoBufferClose(*geom); }