morph


Synopsis


module morph{
group  *morph_obj;
int  morph_type;
flibrary  morph_types;
};

Description

The morph module allows you to implement an object that can dynamically switch between different overlapping implementations. This module is one way that you can implement a dynamic network, where modules are created and deleted automatically. With this approach, you do not have to write any code to explicitly delete or create modules, or make or break connections. You do have to invest some work to define the types properly to get the right behavior.

Input ports

morph_obj

Points to the object into which objects are to be merged.

morph_type

An index into the morph_types array to select which object should be merged into the value of morph_obj. As this value changes, the old object is unmerged from the value of morph_obj and the new object is merged.

morph_types

Defines a library of objects between which to morph. The objects in this library are merged into the morph_obj as the morph_type parameter changes.

Usage

The morph module uses the merge and unmerge facilities of the Object Manager to switch between types. As you change the morph_type parameters, the morph object is deinstanced, the old type is unmerged, the new type is merged and the morph object is reinstanced. The unmerge operation removes any subobjects or values that are not defined in the base type of the morph object.

To use this object, you first define a morph object. This is the object that you should connect to the morph_obj parameter and should contain all of the parameters and subobjects that you want preserved as you switch between types. Then you define two or more morph types that will be merged into the morph object based on the setting of the morph_type parameter. These objects may be derived from the template of the morph object, but this is not necessary.

This example shows how you can use the morph object to create a UI object that switches configuration based on the setting of the morph_type parameter. This example could have been implemented by switching the visibility of the widgets as well. The advantage of using the morph object is that only the widgets that are in use are instanced at any given time. For larger examples, this can improve the performance of the system as it takes some time to instance UI objects even if they are not visible.


flibrary EXmorph1 {
//
// Define the morph object to contain a shell that will be shared by
// all implementations.
//
// We define close, back, next, cancel because we want these values to
// be maintained across all different morphed objects
//
// Any values that we always want reset when we morph are set here
// (or in the individual morph objects)
//
// Any values that we want preserved have default values set in
// EXmorph_test.EXmorph_obj. Here we need to explicitly undefine
// the shell's width and height because it is set by default in UI.v
// or else these values will replace the ones in the morph_obj when
// we change morph_type.
//
macro EXmorph_obj {
UIshell shell {
width = ;
height = ;
};
int close, back, next, cancel;
};
//
// The first morph type is going to be just a simple "Close" button.
// it connects up to the "close" value.
//
EXmorph_obj EXmorph_type1 {
UIbutton Close {
x => (shell.clientWidth - width) / 2;
y => (shell.clientHeight - height) / 2;
parent => shell;
do => close;
};
};
//
// The second morph type is a set of 3 buttons "Back", "Next", "Cancel"
//
EXmorph_obj EXmorph_type2 {
UIbutton Back {
x => (shell.width - 3 * width - 20) / 2;
y => (shell.clientHeight - height) / 2;
parent => shell;
do => back;
};
UIbutton Next {
x => Back.x + Back.width + 10;
y => Back.y;
width => Back.width;
parent => shell;
do => next;
};
UIbutton Cancel {
x => Next.x + Next.width + 10;
y => Back.y;
width => Back.width;
parent => shell;
do => cancel;
};
};
//
// This is the object to instance. It contains the morph object and
// the GMOD.morph module.
//
macro EXmorph_test {
//
// Any values that we want to be shared by the morph objects are
// set here (and explicitly left unset in the morph types)
//
EXmorph_obj EXmorph_obj {
shell {
height = 100;
width = 350;
};
close+OPort3;
next+OPort3;
back+OPort3;
cancel+OPort3;
};
GMOD.morph morph {
morph_obj => EXmorph_obj;
morph_types {
EXmorph_type1 EXmorph_type1;
EXmorph_type2 EXmorph_type2;
};
// Start out with the "Close" -- set to 1 to get "Back", "Next"...
morph_type+IPort3 = 0;
};
};
};

This second example shows how the morph object can be used to create a dynamic visualization network. The first morph type implements an isosurface module, the second morph type implements combination of slice plane and isoline. The threshold value and component parameters are shared between the two different modules.


flibrary EXmorph2 {
//
// Define the morph object to contain a shell that will be shared by
// all implementations.
//
// Here we define the input_field, output_object and parameter values
// that we want to be retained across both morph_types.
//
macro EXmorph_obj {
Mesh+Node_Data &in_field;
// These values are unset by default
// If they have values, these values will be restored during the merge
// each time that the morph_type changes.
float iso_component;
float iso_level;
olink out_obj;
};
//
// The first morph type is going to be just a simple "Close" button.
// it connects up to the "close" value.
//
EXmorph_obj EXmorph_type1 {
MODS.isosurface isosurface {
in_field => <-.in_field;
IsoParam.iso_level => <-.<-.iso_level;
IsoParam.iso_component => <-.<-.iso_component;
};
out_obj => isosurface.out_obj;
};
//
// The second morph type is a set of 3 buttons "Back", "Next", "Cancel"
//
EXmorph_obj EXmorph_type2 {
MODS.slice_plane slice_plane {
in_field => <-.in_field;
};
MODS.isoline isoline {
in_field => <-.slice_plane.out_fld;
IsoParam {
ncontours = 1;
level_min => <-.<-.iso_level;
contour_comp => <-.<-.iso_component;
};
};
out_obj => isoline.out_obj;
};
//
// This is the object to instance. It contains the morph object and
// the GMOD.morph module.
//
macro EXmorph_test {
EXmorph_obj EXmorph_obj {
//
// Define initial values here.
//
in_field+IPort3;
iso_component+Port3 = 0;
iso_level+Port3 => cache((in_field.node_data[iso_component].min +
in_field.node_data[iso_component].max) / 2);
out_obj+OPort3;
};
GMOD.morph morph {
morph_obj => EXmorph_obj;
morph_types {
EXmorph_type1 EXmorph_type1;
EXmorph_type2 EXmorph_type2;
};
/* Start out with isosurface */
morph_type+IPort3 = 0;
};
};
};