Personal tools
You are here: Home / openCMISS / Wiki / Richards Region Notes
Navigation
Log in


Forgot your password?
 

Richards Region Notes

Further Region Developments

  1. Richard Christie, 12-16 August 2003

Regions 1: Outstanding issues

The only remaining task at the time I left was to complete the embedding code I described (and half began) in module finite_element_region.c. With this incomplete, changes to embedding fields will not be automatically updated in the graphics window.

I am quite pleased with the way this is to be handled as it means changes to fields in embedding regions can be dealt with by clients of the embedded region in the same way as local fields. To enable this, the FE_region takes on the reponsibility of logging which FE_regions its nodes (and later elements) are embedded in. However, only if an embedded field (value element_xi) exists is any overhead taken on by regions to handle the possibility of embedding. The overhead is however considerable, and is a strong incentive to free up the field namespaces (so there is one set of fields per true region) which means only regions with element_xi fields defined will have an embedding overhead.

Actually, there is further task that would be nice to get CMGUI to be as completely user-friendly as it was prior to regions. This is to make a nicer region chooser widget, which is currently a textbox. Note that it should be as lightweight as possible, and create its subwidgets on-the-fly as the user interacts with it. Since it needs to display a DAG, rather than a flat list or tree, it needs to remember its current path, and present options of (a) anywhere up its current path to root, and (b) any siblings of the currently selected region, and (c) any child regions (of the region pointed at). It could well keep the textbox to enable users to move grossly away in the region graph.

Regions 2: Freeing node/element namespaces; selections in regions

The next step in the development of regions is to allow more than one true region in arbitrarily deep region graphs. Actually, there are currently two if you include the data_root_region, but this is not a fully-featured region; the data_root_region and any particular reference to “data” in the program is to be removed in this step and replaced with specific references to which nodes of which region constitute data for any given operation. The function for synchronising the children of the root_region and data_root_region will no longer be required (however, move it from cmiss.c to cmiss_region.c and archive it; it was tricky to write in the end and may be useful again).

One aspect of the data_root_region that will be kept in a modified form for all the non-root regions in the graph is the inheritance of the FE_field_list from the root_region. In order to make stage 2 of region development a more reasonable size, stick with one FE_field namespace, keep it in the root_region and use an internal flag or pointer in FE_regions to use it rather than have their own (could even keep a pointer to the same list in their fe_field_list member, but this should be done with due care!). This means you will keep the existing computed field manager, plus its code for synchronising with the root_region fe_field_list unchanged.

The most significant ramification of the changes in stage 2 region development are on selections (including on tools that use them), and coordination with scenes since we will now be dealing with more than just a single list of groups (and a coordinated data group list). There are additionally trivial, even optional changes to current commands and file formats to handle the new structures.

The Selection Object

This is an object attached to Cmiss_regions like FE_regions (see finite_element_region.c for details how). It should spread throughout the region graph like a virus; add one to a cmiss_region and the Selection object will make more such objects for all the child regions; Add a child region to a cmiss_region with a Selection object and it will do the same (obviously this means the Selection has to monitor changes to its owning Cmiss_region). There need only be one selection object per region. (I envisage Scenes attached to regions spreading in the same way, only they will be named to permit multiple renditions).

The selection object will have one flag to indicate whether the entire cmiss_region is selected. If so, no other subobject should/need be selected as well. This means there will finally be a way of selecting entire groups/regions for operations. All other subobjects of a region that need to be selectable (except for subregions which will have their own selection objects) will need to adhere to some interface (such as some macro definitions, rather like the current any_object) in order to work within the confines of the selection object. They will need to obey certain functions like begin/end change, clear all, select/unselect, merge selections etc. This means it will be possible to select no nodes in the graphics window (by clicking in the middle of nowhere) and all other selections are erased as you would expect. Of course, it would be possible to put a copy of the current selection objects (node, element, element point) within the Selection object, however, as more and more subregion objects become selectable (graphics, fields etc.), the Selection object would have to know too much, so the best long-term approach is to provide an interface and allow the various subobjects the chance to complete their own means for selecting themselves (element points in particular definitely need their own means for this).

Note I have been purposefully vague about the exact nature of the interface and how to implement it; I know the means for doing what I have described, but have only really put half an hour of work into it: I am confident you would come up with same or better means if you thought about the problem (and nowadays would try to convince you to use C++ interfaces to make the subregion selections work with strong type-checking). I believe it is more useful for me to describe how it should work and what issues have to be taken into account.

Issues:

  • Nodes, elements and element points should be provided initially. Child FE_regions with master FE_regions should not maintain separate node/element/element point selections from their parents. However, they themselves need to be selectable via the overall flag, and other subobjects such as graphics will eventually also need to be selectable. I believe the Selection object in regions with masters should appear as if the node/element/element point selections belong to them, when in reality they belong to their master's region.
  • Child selections will need to know if they are selected on account of whether they have an ancestor that is selected in its entirety. Perhaps the parent selects the “all selected” flag for all children, and them to theirs: think about this.

There are possibly complications when multiple parents battle for selection; there are definitely issues to think through when you unselect with multiple selected parents. For example, if A and B and are selected, child-of-both C is definitely selected. If B is unselected, is C still selected on account of A? Or are only the non-C parts of A still selected. What happens if just C was unselected? You need to determine a policy for how this is to work.

  • Objects such as the node_viewer and node_tool that rely on selections to choose the objects they are working with need to be modified. Firstly, the data_viewer and data_tool can be eliminated. At the very least, this requires the remaining viewer and tool to have a region chooser, to select which of the regions it is viewing or modifying nodes in. This may well be an acceptable interim solution. However, users will quickly tire of clicking on a node only to find out it isn't in the region the node_viewer or node_tool is watching, so we need a way for the region to be determined from the selection object, and appropriate callbacks to be made informing of this. This is not so easy; the tool could conceivably ask all selections for change messages, but this is probably a mistake. A better approach is for parent selection objects to collate changes in their child region selections and pass them on to their clients. This could be expensive if not done carefully.

There will need to be hierarchical begin/end change calls to delay selection change callbacks until all changes have been completed. This is especially so if selection changes are propagated up the region graph.

Command and File Changes

Should remove all ngroup, dgroup, egroup commands and replace them, in most cases with “group” or “region” instead, in each case specifying the entire path to the region, or parent region if the command is to create a child. Different commands will be required to create groups (regions whose FE_regions have a master FE_region), and true regions. Adding and removing nodes and elements makes sense only for groups more than regions, although “removing” objects from the master region is the same as destroying them, so could consolidate commands here; defining faces works with either.

Reading in data files will require some thinking for backward compatibility. Perhaps “gfx read data” can remain a deprecated legacy command, that ensures there is a true region child of root_region called “data” which serves as the new data_root_region to contain the data and data groups read in. Alternatively, I suggest writing a fixcom script to replace the first instance of this command with two others, one to create the “data” region, and the other a “read nodes” command which additionally says which region is the root_region for this file: “/data” (there may be more commands; see “Ramifications for Scenes” later). All subsequent read data commands in the comfile only need the latter of these two replacements. Obviously some people's comfiles (those that call other comfiles) may repeatedly warn that “region /data already exists”, but that is easy for them to fix. There is one real gotcha, however: embedding. The elements that the data/nodes are embedded in will not be in the root region for the data file, but in the true root_region. Possible solutions to this are to have another option on the read command to specify the root region for embedding. However, a possible solution to all the above is to write a script to convert the data files to have a region called “data” wrapping them, so the root_region for the file is the root_region for the global data. This requires a modification to the exregion format; see below.

Eliminate data_points: only need node_points. Depending on the approach used to deal with data files chosen above, it will be necessary to modify all the “gfx modify g_element BLAH data_points ...” commands to read “gfx modify g_element data/BLAH node_points ...” or similar. Then remove data_points as an option.

May wish to modify exnode/elem/region file format to add a “Region : NAME” specifier. This will allow the entire data structure to be exported in a file. Perhaps regionml/fieldml is ready for action instead (and please DO allow space for selections, computed fields and scenes etc. to be saved in the appropriate places within the cmiss_region). To be able to reproduce a DAG structure as opposed to a tree, need a means to say two region paths refer to the same region.

May wish to consolidate read/write nodes/elements into read/write regions.

Many other commands will benefit from allowing a relative root region to be specified for an operation. The write nodes/elements/region commands and functions are written with the concept of having part of the tree written, and exported relative to a chosen root. This requires the corresponding read to similarly state where in the DAG the information is to go.

May also have command options to “upgrade” a group to a true region when reading in a file, to allow the heart and the lung to be read in from the existing files. This requires a bit of careful thought, and may be something you ask people to do themselves (ie. Putting Region: instead of Group: in their .ex* files).

DAG or Tree?

I think you should go hard out and make it a DAG from the word go: your option. All that is needed is to remember that two region paths may refer to the same region. This just requires commands and specifications in input files to associate the two paths together. It also requires care with algorithms such as rendering and file export so that the same region is not rendered or exported twice. I think I already handled this in export_finite_element.

Ramifications for Scenes

Once the selection object is within the regions, and data is removed, the number of arguments in the constructor for a region's graphical element diminishes even further: possibly to just the cmiss_region itself. However, now there is a need to create scenes and graphical elements from regions in a possibly quite deep hierarchy – or DAG.

The problem of coordinating scenes and graphical elements is the reason why Regions Stage 3 makes Scenes into objects attached to regions. They are then automatically synchronised with the model. Furthermore, Scenes and Graphical elements become equivalent. It may be relatively simple to make this part of Stage 2, but I will delay explaining the issues until Stage 3 below, and look at simply getting Scenes to work with regions now.

I was going to suggest that an easy way to get this going with minimum changes would be to get scenes automatically created with the name of the region, and added to the parent region's scene. This has the following drawbacks:

  • May/will also want a graphical element for each scene; automatically creating one will double the number of items in the scene and they will be differently named.
  • Regions with multiple parents will appear twice.

An even simpler method is to leave it semi-manual:

  • Get scene “default” to monitor changes to the root_region and create graphical elements for its child regions exactly as now.
  • When the data region is create by fixcom, can also create a “data_scene” which monitors children of the data region and adds graphical elements appropriately. Also add the data_scene to the default region. I also suggest making the “data” graphical finite element invisible and empty, otherwise there will be two renditions for every data point.
  • Similarly, with any other deeper nesting of regions, leave it up to the user to establish how they want it to work.

As you can see, neither option is particularly nice: you want Stage 3 Scenes in Regions! Don't waste too much time trying to synchronise scenes with the model graph: they are not up to it.

Development Time and Payback

2-3 months, depending on how tricky the selection object is, and how many other features of the program introduce “gotchas”. Other delays could be caused by discovering a need for sophisticated messaging up and down the selection graph (= graph of selection objects attached to regions).

The payback is that the node and element namespaces are unrestricted as long as you are prepared to make a new, true region for each new namespace. Also, the models exists as a DAG, a much more powerful structure than a flat list of regions with namespaces. Finally, there will be a selection system that allows whole regions to be selected, and cleans up all the problems with the previous, separate selections, namely that they work independently of each other. Of course, you could even have multiple selections in the program, but that would probably be too difficult for users to understand!

Regions 3: Scenes in Regions, Fields in Regions.

I will be a little more brief in this section, partly because there are fewer legacy problems as it really starts to fit into place, and partly because I have not given quite as much detailed thought to them. Also, it looks like it will be possible to merge code at at least one point in the middle of this stage, namely after Scenes are put in regions.

Scenes in Regions

I was never happy with the separation of models and graphics in cmgui. It always meant there were things that appeared in the Scene/graphics part that really should have been part of the model: transformations is one of these, however, that will be dealt with in the section on fields, below. More significantly, hierarchical grouping structures existed only in the graphics, not in the model.

A more sensible approach is to make graphics merely a rendition of the model. This can be achieved simply by attaching to each region a Scene object which provides a rendition of it. In order to permit multiple renditions of the same model, Scene objects should be named. Like the selection objects, they should spread down the region graph and populate it with same-name renditions of all its parts.

Let us again use the word Scene as the name of the graphical rendition object we attach to a region. Each Scene has a name, and it creates or associates itself with like objects of the same name attached to child regions of its owning region. If the user creates a scene “bob”, a scene “bob” will be created for each region in the model; “bob” can be used to refer to the entire scene graph, which works together to produce a rendition of the entire model graph.

Nifty things and issues with setting up the rendition in this way:

  • Graphical finite elements and Scenes become one in the same.
  • You can put static graphics objects in the Scene for a Region using “gfx draw”.
  • Settings in the graphical element, along with their graphics object, appear in the same list as static graphics, eg. “node_points coordinate coordinates material bob...”. The legacy graphics commands “gfx create lines” etc. should be done away with, if they haven't been already. However, consider how similar they operate to the graphical element “settings” in the Scene in the Region: “gfx create lines coordinate coordinates” could exist as a settings in the root_region, which never had a graphical element prior to this.
  • I also anticipate that lights may be listed members of the Scene – in the same list as graphics objects.
  • You cannot draw (our old) scenes within scenes; they live and die with regions. You have to create a child region to get a child scene. This may upset some people, but it truly reflects the fact that cmgui is a modelling package, not a graphics package. None of these changes limit the package's ability to display what people want: you just have to start thinking “everything is part of the model”.
  • Partial model graphs. It may be worth considering whether it could be useful to allow part of the model graph to be populated with a named scene. But not too long.

The new Scene will require hierarchical begin/end change functions to limit messages. Also, Scenes will require callbacks from same-name Scenes attached to child regions, to allow changes to propagate up until they reach the root scene being viewed in a window. This will usually, but not necessarily, be the root_region.

One tricky problem is what to do with the overlay scene – where to put graphics that are overlaid in the graphics window. It always irked me that a Scene viewer was able to display two scenes, and in slightly different ways. I have a real solution for this, described in section “Regions into the Future”. An interim solution could be to allow a list of graphics objects to be added to the scene viewer. You may have a better idea.

As long as transformations are left as they are now, putting Scenes in Regions could be completed and checked into release code without having to do the following.

Fields in Regions

The final critical requirement of regions is to free up the field namespace. By this I mean the following:

  • Each true FE_region should have its own FE_field namespace. This enables a prolate “coordinates” to coexist with RC “coordinates” as long as they are in separate regions.
  • If this is so, each Cmiss_region should have its own computed field namespace, via a Computed Field object attached to the region. The Field object is where the region stores data. By contrast, the FE_region object provides a finite element field representation that may be shared by and presented externally by fields defined in the Field object.

There are good reasons for separating the field namespaces:

  • It more clearly associates a region with the fields it mainly uses. It allows a high degree of independence of one region from another, which may have payoffs if the program is run in multiple threads or on a cluster.
  • Fields can also be defined in parent regions and supply values applicable to all children.
  • Like in coding, it is good to avoid global variables, which is what one field list is like. The flux of some ion in a cell of the left ear probably doesn't need to be presented in the same list as the stress in the left knee. In fact, consider how big a global list of fields could become and how specific the names would need to be to model the whole body: it's not an option.
  • Embedding is more efficiently dealt with if the embedded fields are not defined globally; only those FE_regions with element_xi fields would need to take on the overhead of dealing with embedding.
  • Computed Fields, defined locally in regions are the logical means for providing generalised transformations to replace the limited 4x4 transformation between Scenes/graphics. That would make them part of the model, where they belong. This will be looked at in a later subsection.

Freeing up the field namespaces involves simply removing the “fieldhack” inheritance of the fe_field_list from the root_region (see Stage 2), and making a Field object attached to regions for containing Computed fields (Perhaps these should be called Cmiss_fields, as Computed is more-or-less redundant). The commands for modifying computed fields need to specify which region the field is in; the field choosers in the graphical element editor also need to be switched to the lists of fields in their regions, which should not be too difficult.

More work will be required once “proxy” fields are introduced as described in the following, as well as hierarchical fields introduced in section “Regions into the Future”. Since these will provide relationships between fields in parent and child regions, it will be necessary to be able to choose “a field from a region” on many of the dialogs, but the flexibility that introduces will be great. In fact, such region choosers are need to access any field from other regions, eg. Constants fields in parent regions may supply values for all their children.

Transformations and Fieldspaces / Proxy Fields

Transformations are simply relationships between fields. They represent concepts like “The coordinates of the chair are offset from those of the room by x,y,z”. Each region should be free to use its own origin, coordinate system, units (for any of its fields) and so on. It is only once a region is placed in a parent that relationships between parent and child fields need to be established since only then does one care where the child is and what is values represent in terms understood by that parent.

One of the issues with trying to represent transformations as computed fields is that very often the same transformation applies to different fields. For example, if we have “coordinates” and make computed field “scaled_coordinates” by multiplying the z component by 2, we would logically expect both fields to transform into their parent's space in the same way. It would annoying to have to re-specify transformations of every field into their parent's space. It is totally unreasonable to expect to have to specify these all the way up a deep region graph.

My suggestion for dealing with this issue is to clarify the two concepts of field that we currently to merge into one. This is best illustrated by an example. Suppose we have two coordinate fields undeformed and deformed which give two positions of, say, a heart as it grossly deforms. (Note it is not adequate to say they should be different times of the same field: what if you wanted to scale that field?). A mesh is used to define the extents of the object. If both fields are meant to transform identically into the coordinates of a parent torso region, we benefit from defining a common object representing the space they are in. This space is not just in the mesh but over the entire coordinate system and in whatever units we wish to use. In 3-space it should be like a 3-value field, but its value is any point in the space. Since it represents any point in the fieldspace, I will use the term “proxy” field, but you may well think of a better name. Here's an example of its definition:

'gfx define field heart_space proxy number_of_components 3 coordinate_system rectangular_cartesian units mm'

This could be how you assign it to other fields:

'gfx define field un/deformed ... proxy heart_space'

To define a transformation to a parent's space, just use any computed field, but specify the proxy field as its source field:

'gfx define field heart_in_parent_space offset field heart_space offsets 1 2 -3 proxy /path-to-parent/parent_space_proxy_field'

Note that in the above, the proxy argument declares what space the transformed result is in.

The proxy field contains everything common about all the fields that use it. The introduction of this concept to the program is not to be taken lightly: most fields in most regions will require a proxy field to be established for them. It is not just about coordinate fields, since it can describe relationships between any fields, if only to transform between different units. It will involve a bit of work, and it should be a part of the model's file format when saved. You are not restricted to 4x4 matrix transformations, although the rendering may choose to use that method if it the transformations can be described that way: otherwise it will have to manually calculate the transformed values (or use more sophisticated vertex-shader programs to do transformations on newer graphics hardware!).

When graphical settings use a particular coordinate field, their graphics are transformed in the manner of that fields's proxy field. (Perhaps it is possible to have none, in which case the graphics just live in some default space; RC? ISO units?) Static graphics objects and lights will also need to have a particular proxy field chosen for them if they are to be similarly transformed.

So who owns these proxy fields and transformations? Clearly it is either the parent or child region, or some combination. I think they should belong with the child purely because there are usually many children and one parent, so the namespaces are kept independent. However, there will be synchronisation issues for transformations involving multiple parents. Cross that bridge when you need to. It is solvable, and in fact in many cases only one parent cares about the transformation.

Development Time and Payback

This is a little more difficult to determine. I would say 3-6 months, especially if hierarchical field choosers are implemented in the same step. There are also a few more ideas to be fleshed out before implementation.

The payback is that you will have an unbounded number of field namespaces; RC lungs and prolate heart can be loaded simultaneously even if they define “coordinates” with different coordinate systems. Transformations are part of the model, and have all the flexibility of computed fields. Field values can be stored anywhere in the model DAG, enabling, eg. regional constants.

Regions into the Future

This section will be brief and to the point. These are icing on the cake things, but all in the great big region vision.

  • Views, viewing volumes and the overlay scene. Consider making all the views and transformed volumes of each 3-D scene viewer into regions in the model graph, with proxy-field style transformations describing modelview and projection matrices. The attached Scenes are exactly where the overlay graphics need to be put to appear appropriately in the window. You could even render viewing frustums from other views. Note there are issues with visibility of the overlay and the views: it is not always wanted.
  • Similar to the above, the Faro arm pointer should be a field variable in its own region. The mouse pointer should be represented by field variables – in the window space. Every data manipulation in the program could be converted into field manipulations.
  • There needs to be a new type of field that is defined on a parent region purely by noting its corresponce to some listed fields in its children. This “hierarchical” field will enable users to specify operations in one region (closer to the root) and it will operate appropriately on all descendants. Users will love it.
  • There could be additional regions that are “Instances” of another region. Currently the DAG concept is used to denote that two different paths may identify the same region, rather than two regions that happen to always be the same. You probably want both of these, if only to make up for what will be taken out with the current Scenes.
  • Use C++, it is a better language, faster to develop, the STL is rich, powerful and quite established now. You can even use Namespaces to avoid having to write Cmiss_OBJECT_NAME all the time.

Otherwise, Enjoy!