![]()
![]()
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);
}