Lee A. Butler
Michael John Muuss
Paul J. Tanenbaum
John R. Anderson
Robert G. Parker
Ronald A. Bowers
Christopher T. Johnson
Eric W. Edwards
Ballistics & NBC Division
Survivability/Lethality Analysis Directorate
U.S. Army Research Laboratory
Aberdeen Proving Ground, MD 21005-5068 USA
Revising BRL-CAD to use a new database format (v5) is intended to provide an evolutionary, upward-compatible capability with a minimal implementation and deployment burden. Overall, the goal is that there will be few, if any, visible changes to the end-user. Specific goals include:
The database is organized as a directed acyclic graph (DAG), which comprises
The database access library stores objects as a collection of data with a globally unique name and places no interpretation on the content of those data. The object is the smallest granularity of an item in the database; objects must be read from and written to the database in a single atomic operation.
In the case of librt, each database object will contain exactly one combination node or leaf (solid) node.
The Object Header consists of:
Part | Element | Comments | ||||
---|---|---|---|---|---|---|
Object Header: (not compressible) |
Magic1 | Required | ||||
HFlags, AFlags, BFlags | ||||||
Object_Type (Major_Type, Minor_Type) |
||||||
Object_Length | Required | |||||
|
Conditional on flag bit N, Required for Application Data |
|||||
Object Interior: (individually compressible) |
|
Conditional on flag bit A (ZZZ compression) |
||||
|
Conditional on flag bit B (ZZZ compression) |
|||||
Object Footer: (Not Compressible) |
Padding | As Required to maintain 8-byte object boundaries | ||||
Magic2 | Required |
????Need a description that says that an object can now have (1) EITHER an attribute OR a body, (2) BOTH an attribute and a body, or (3) NEITHER an attribute nor a body.
The routines db_get_external() and db_put_external() are used to move objects in external format between memory and the database disk file. The routines db_wrap_external() and db_unwrap_external() are used to wrap and unwrap the
(??? Object_Body or Object_Interior ???)
(already in external form) in a standardized database object's wrapper.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Wid |
N |
Wid |
r |
DLI |
|
Wid |
P |
r |
r |
ZZZ |
|
Wid |
P |
r |
r |
ZZZ | |
|
00 |
|
01 |
|
10 |
|
11 |
|
|
The DLI flag is not available to the higher database access layers.
Implementation note: Before writing a new object into the database in a free area, the library should read the object header from the database and confirm that the space is indeed free. Similarly, additions to the end should be checked by ensuring that the file hasn't been extended. In case the check fails, the database write should fail, the user should be notified, and the internal library mode (not the operating system file access permissions) should be changed over to read-only access so that no further attempts to write will be issued. These checks will provide protection against two or more users trying to modify the same database simultaneously and accidentally stepping on each other. In the NFS world, file locking isn't a strong enough assurance.
|
Associated Length Fields
|
|
|
|
|
|
|
| |
The Object_Wid flag, at the high end of HFlags, encodes the width of the Object_Length field. The Name_Wid flag, in bits 3 and 4 of HFlags, encodes the width of the Name_Length field (when the name element is present; see the N bit, shown later.). Attribute_Wid (or Body_Wid, as the case may be) encodes the width of the Attribute_Length field (when the Object_Attributes (or Object_Attributes) element is present. http://ftp.arl.mil/~mike/papers/brlcad5.0/newdb.html - bbitSee the P bit, below.)??????????.
The rationale for allowing the width of the Object_Length field to be specified independently of the other widths is to save space on objects in which the values in many of the length fields nearly overflow the specified field width, so that their sum requires a wider field. For example, for four 255-byte interior fields, the corresponding length fields need be no more than 8 bits wide, so the choice Interior_Wid=00 suffices, but their combined length of 1020 bytes would require Object_Wid=01. Because all of the length fields besides Object_Length must have the same width, the largest of the values stored in these length fields determines the value of Interior_Wid required. Both Object_Wid and Interior_Wid may vary from object to object. It is expected that the routines that write an object to the disk will use the narrowest width possible for each object.
Each of the N and the two P flag bits indicate the presence (1) or absence (0) of the corresponding element. This eliminates the need to specify a length of zero for optional fields that are not present in a given object.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The remaining flag bits ``r'' in HFlags, AFlags, and BFlags are reserved for the design committee to waste on additional optional fields in the object.
0
|
|
Major_Type |
Minor_Type |
Each different Major_Type value is assigned to a different class
of database objects. The following values are defined in this specification:
Value
|
|
Reserved |
|
BRL-CAD Nongeometry Objects |
|
BRL-CAD Geometry Objects |
|
Attribute-Only Objects |
|
Experimental Binary Objects (Unrecorded Structure)
(Minor Type Unspecified) |
|
Uniform Array Binary Objects, (Type Described
in Minor Type) |
|
MIME_Typed Binary Objects (Attribute "mime_type"
Describes Format) |
|
Registered-Type Binary Objects |
|
First Non-ARL Type Begins Here | |
The remainder are available for extending the types of objects that may be stored in the database, allowing BRL-CAD users to extend the database for their own particular purposes far beyond what the "attribute" method permits.
Major_Type = 1
BRL-CAD Nongeometry Objects
value
|
|
Reserved for sanity check |
|
Combination |
|
Grip Nongeometric |
|
Joint Nongeometric | |
?????Should "Grip" and "Joint" objects be of this type, or Major_Type = 2?
??????Consistency: Some tables have titles and other do not. Do we care?
Major_Type = 2
BRL-CAD Geometry Objects
Value
|
|
Reserved for sanity check |
|
Torus (TOR) |
|
Truncated General Cone (TGC) |
|
Ellipsoid (ELL) |
|
ARB |
|
ARS |
|
Half-Space (HALF) |
|
REC (TGC Special Case) |
|
Polysolid |
|
B-Spline Solid |
|
Sphere (ELL Special Case) |
|
n-Manifold Geometry (NMG) |
|
Extruded Bitmap (EBM) |
|
Volume (VOL) |
|
ARBN |
|
PIPE |
|
Particle |
|
RPC |
|
RHC |
|
EPA |
|
EHY |
|
ETO |
|
Grip Nongeometric |
|
Joint Nongeometric |
|
Height Field (HF) |
|
Displacement Map (DSP) |
|
2d Sketch |
|
Extrude |
|
Submodel |
|
BOT |
|
Cline |
|
User-Provided Extensions | |
The details of these Minor_Types are provided in Section IV.
For example, if several objects need to have the same shader parameters, it would be possible to create one attribute-only object to hold these common attributes and serve as a simple form of "macro". Objects that needed to share these attributes could all reference the same attribute object. If the attribute object is altered, then all of the objects that reference it would be updated together. Without this capability, the user would have to update each element individually to alter the attributes.
Conventions will have to be established regarding which attributes of an attribute-only object will be used when a macro reference is performed. For example, rt shaders will only be interested in the value of the "oshader=" attribute, while librt's tree-walker might also be interested in the "rgb=", "giftmater=", "nsn=", "material=", and "los=" attributes (assuming that a convention was developed so that a combination could macro-reference an attribute-only object too).
An attribute-only object may not have an object body; thus, flag bit B must always be zero for this type of object.
As used by the rt family of applications codes, these attribute-only objects will contain "macros" for shaders. The shader name and its parameters shall be encoded as a single ASCII string, which is the value of the "oshader=" attribute. An rt shader named "macro" (or equivalent) would take a single parameter "obj=", which would specify the name of the attribute-only object in the database from which the actual shader and shader parameter information would be extracted.
There will be one attribute-only object with a reserved object name of "_GLOBAL" that will be used to contain various kinds of states that are global to the entire ".g" database and that had previously been found in the database header itself. There will be the following BRL-CAD-specific attributes whose meaning is predefined for the _GLOBAL object:
MGED and standalone commands must be built to store/extract these opaque?? binary objects between a ".g" file and stdin/stdout/auxiliary files. A user might want to use those same MGED commands to store/extract the binary object body of any object for external processing. An easy example to imagine is the importing and exporting of texture maps for external processing, but the same commands could be used for importing and exporting solid parameters in their external binary form.
These objects may be referenced in combination nodes, for organizational purposes, but they cannot be drawn in MGED or raytraced, and doing so would result in a warning message being printed by the tree walker as that arc is traversed. This class may be used by all applications and layers.
The data's purpose may be placed in the "purpose=" attribute. (????????Need a table/registry of presently known values for this attribute.)
Routines that retrieve bulk binary objects should check the minor type and the "purpose=" attribute and send a warning message in the event of a mismatch, but best-effort processing of the object should continue. This will permit some degree of error checking, which should benefit novice users without standing in the way of "creatively" reusing one set of data, (e.g., using one array of values as both a height field and a bwtexture). This allows common data perversion practices, such as interpreting an array of floats as an array of bytes, to continue.
Each application will need to have its own syntax for the user to specify whether the data source is an outboard file or a raw-binary object. For example, the current RT sh_texture module uses the keyword file="name" to indicate an outboard file; that might be supplemented with an additional obj="name" possibility for retrieving from an inboard raw-binary object.
Point of Discussion?????Has ramifications... we have to implement type
advising, so that applications that use these data can compare the
type provided in the minor type code with the type that they're expecting
and advise the user (with a warning message) that there is a potential
type mismatch.
|
|
|
|
|
|
|
|
r |
r |
Wid |
S |
Atom | |
The 3-bit ``Atom'' flag indicates the fundamental data type of the atomic
elements in the array according to the following scheme:
|
|
Reserved for sanity check |
|
Reserved |
|
float (IEEE, network order) |
|
double (IEEE, network order) |
|
8-bit int |
|
16-bit int |
|
32-bit int |
|
64-bit int | |
The ``S'' bit indicates whether an integer type is signed (1) or unsigned (0). Floats and doubles (i.e., atomic types with the highest atom bit equal to 0) are explicitly signed, so they will have the ``S'' bit equal to 1. (The bit patterns corresponding to unsigned floats and doubles are reserved for possible other use.)
The 2-bit ``Wid'' flag specifies the length (in atomic elements) of
the array elements:
|
Array Element
|
|
|
|
|
|
|
| |
The remaining Minor_Type bits ``r'' are reserved for the design committee to waste on gratuitous other stuff, possibly including extensions of the ``Atom'' and/or ``Wid'' flags.
As examples, data in PIX(5) format, which might be used for a texture map, would have Minor_Type ``0010 0100'', indicating a triple of unsigned char, and CMYK data might be stored with Minor_Type ``0011 1011'', indicating a quadruple of doubles.
The data's purpose (e.g., height field, texture, bump, displacement, etc.) may be placed in the "purpose=" attribute. ?????Point of Discussion???(Need a table/registry of presently known values for this attribute.)
A Minor_Type of 2 indicates that this is a database header.
The name is specified in 8-bit ASCII. There is no support for UNICODE. The name is null-terminated, and the null byte is included in Name_Length.
See the section on DLI flags. In the case of Free objects, the name is not retained. Undeleted objects have a different DLI flag code.
aname1=value1, aname2=value2, ..., anameN=valueN
binding attributes to values.
These are ASCII strings of unlimited length. These attributes are intended for direct use by programs. There will be a WWW registry of attribute names presently in use to prevent two application developers from using the same attribute_name for different purposes.
For attribute names and attribute values, The decision was taken to support 8-bit ASCII only. The on-disk encoding of this will simply be:
aname1 NULL value1 NULL ... anameN NULL valueN NULL NULL
where NULL represents a byte with all bits zero. The NULL in place of anameN+1 signals the end of the attribute data, simplifying the job of the reader.
Every object in the database may have zero or more attributes attached to it; the meaning of these attributes will vary depending on which application or library processes them.
There are several aname conventions that all BRL-CAD applications are expected to respect. There will be a WWW extendable registry of "in-use" anames, so that independent applications developers may select aname strings for their own use without fear of name conflicts later. The initial registry would include:
Magic1 (1byte)This is why we have chosen the 8-bit size for our chunks. Pad bytes are inserted as necessary in the Object Footer immediately before the second magic number so that the final byte of the object is the Magic2 byte. The pad bytes are not counted as part of the Body_Length, but are counted as part of the Object_Length.
HFlags = 000xxxxx (1 byte)
AFlags = 0000xx00 (1 byte)
BFlags = 0000xx00 (1 byte)
ObjType = Free (2 bytes)
ObjLen = 7 (1 byte)
Magic2 (1 byte).
The minimal valid object is thus the following Free object:
Magic1 (1byte)The header of the database will always look like this:
HFlags = 00000010 (1 byte), Wid=00, N=0, DLI=02
IFlags????? = 00000000 (1 byte), Wid=00, A=0, B=0, ZZZ=000
Object_Type = RESERVED (2 bytes)
Object_Length = 1 (1 byte)
Pad (1byte)
Magic2 (1 byte).
Magic1 (1byte)
HFlags = 000xxx01 (1 byte), Wid=00, N=0, DLI=01
IFlags????? = 0000x000 (1 byte), Wid=00, A=0, B=0, ZZZ=000
Object_Type = RESERVED (2 bytes)
Object_Length = 1 (1 byte)
Pad (1byte)
Magic2 (1 byte)
The hex and ASCII dump of this object would look something this:
The minimal valid allocated database storage object (with an Object_Name, no Object_Attributes or Object_Body) would thus be:
76 01 00 00 00 01 00 35 |v......5|
Magic1 (1byte)Without the padding, this (rather useless) object would be 10 bytes long. Given the rounding requirements, it is clear that all allocated storage objects in the database must be at least 16 bytes long. A database object with a minimal Object_Body would need 12 bytes, which would need to be padded out to 16 bytes as well:
HFlags = 001xxxxx (1 byte), Wid=00, N=1, DLI=00
IFlags ?????= 0000xxxx (1 byte), Wid=00, A=0, B=0, ZZZ=000
Object_Type = OPAQUE?????_BINARY (2 bytes)
Object_Length = 8 (1 byte)
Name_Length = 2 (1 byte)
Object Name (1 character + null byte) (2 bytes)
Pad (6 bytes)
Magic2 (1 byte).
Magic1 (1 byte)
HFlags = 001xxxxx (1 byte)
IFlags???? = 00x1xxxx (1 byte)
Object Type (2 bytes)
Object Length = 16 (1 byte)
Name Length = 2 (1 byte)
Object Name (1 character + null byte) (2 bytes)
Body Length = 1 (1 byte)
Body Data (1 byte)
Pad (4 bytes)
Magic2 (1 byte).
16
|
15 |
0
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Consider the external form of a sample object with the HFlags byte set
to 01100000 (so Object_Wid=01, N=1) and the Interior_flags byte set to
01110000 (so Interior_Wid=01, A=1, B=1, and ZZZ=00). All length fields
are thus 16 bits wide, each of the Object_Name, Object_Body,
and Object_Attributes elements is present, and the object
interior is not compressed. Then the object might have the following byte
layout:
16
|
15 |
0
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|||
|
|
||
|
|
||
|
|
|
In practice, this particular object could have been encoded with 8-bit-long fields.
The reason 1 byte of magic number at each end of an object suffices is because the byte before the Magic1 byte of an object should be the Magic2 byte of the previous object. That fact plus the 8-byte alignment constraint will make it possible to reliably locate the start of each undamaged object in the database even if portions of the database have been corrupted.
Extension mechanism: If additional database fields need to be added in subsequent revisions, they will be placed in the Object_Footer just above any pad bytes. The new fields will seem to older versions of the database reader to be pad bytes, and so will be silently skipped.
When the ZZZ bits are 000, the object has not been compressed and needs
no special processing. When the ZZZ flag is nonzero, the on-disk object
has been compressed. When the interior of a compressed object is needed,
an extra processing step is added: after reading the object into memory
in a db_external structure, the decompression algorithm is run on
the interior of the object, resulting in a new db_external structure.
The table of values
for the ZZZ flag has been given earlier.
Decompression
|
Decompression Magic1 |
Magic1 |
Flags |
Flags |
Object_Type |
Object_Type |
Object_LengthB |
Object_LengthA |
Object_Name |
Object_Name |
Object_Interior
|
(compressed) Object_Attributes |
pad |
Object_Body |
Magic2 |
|
|
pad |
| Magic2 | |
After decompression, the object would look as described earlier, but the value of ObjectLength in the decompressed object would be different than the value of ObjectLength in the compressed object.
Decompression of compressed objects will be automatic and will be performed only when needed. For example, objects will not be decompressed when scanning the database (e.g., to build the in-memory table of contents). Compression will only be performed by user command; it is envisioned that MGED will be given compress and decompress commands to allow the user to have complete control over the speed/space tradeoffs.
Compression support is mandatory for any implementation of a database reader library; it is optional for an implementation of a database writer library.
Point of Discussion????Proposal: The Object_Attributes and Object_Body should be separately compressed. This way, if only one or the other is needed, only that portion needs to be decompressed. Also, the ASCII strings of the attributes and the binary data of the body are likely to need different treatment for compression. Some compression algorithms can be given "hints" that they are compressing 16- or 32-bit-wide binary data, rather than streams of 8-bit characters.
????Statement about the compression algorithm being specified by ZZZ bits in AFlags for attributes and BFlags for body.???
In the compressed form, an extra field that has the uncompressed length
is added.
Decompression
|
Decompression
|
|
|
|
|
|
|
|
|
|
|
(Compressed size)
|
|
|
|
(Compressed)
|
(Compressed size)
|
|
|
|
(Compressed)
|
|
|
| |
|
|
|
.
|
|
|
|
.
| |
where the length of each object is potentially quite different.
Each (nonfree) object must have a name that is unique in a global name space. The object's name is its retrieval key. In its most basic form, the database can be thought of as a relational database (table) with a single key.
Traditionally, BRL-CAD databases with no commonly named objects can simply be concatenated. When this is done, it results in a second header in the middle of the file, which makes such concatenation easy to detect. (Note: If two or more objects have the same name, when the concatenated database is opened, there will be only one object with that name--the last one encountered.)
|
|
|
|
|
|
| |
The 2-bit ``Wid'' flag specifies the size of the ``Matrix Count'', ``Leaf Count'', ``Expression Length'', and ``Expression Depth'' fields with the same semantics used in the ``Wid'' flags of HFlags, AFlags, and BFlags above. The ``Matrix Count'' field indicates the number of matrices in the ``Matrices'' section, the ``Leaf Count'' field indicates the number of leaves in the ``Leaves'' section, and the ``Expression Length'' indicates the sum of the number of operators and the number of operands in the ``Expression'' section. The ``Expression Depth'' field indicates the maximum size of a stack (in number of operands or subexpressions) required to parse the expression.
The ``Matrices'' section is a list of matrices, each recorded as 16 IEEE doubles in network order.
The ``Leaves'' section is a list of 2 * LeafCount members:
|
|
|
|
|
|
|
|
. .
|
|
|
| |
where ``name_i'' is the name of the ith leaf and ``mi_i'' is the index into the ``Matrices'' section for the corresponding matrix. To avoid having to store identity matrices, the ``mi_i'' value of 2w - 1, where w is the value encoded by the ``Wid'' flag (See the ``Wid'' flags of HFlags, AFlags, and BFlags above.) (in other words, all bits of ``mi_i'' are set), is defined to indicate the identity matrix.
The ``Expression'' section records the tree in postfix (a.k.a., reverse
Polish) notation using the following encoding:
|
|
operand |
|
union |
|
intersection |
|
difference |
|
symmetric difference (XOR) |
|
complement (NOT) | |
Each time the ``operand'' token is popped from the stack, it will be interpreted as ``the next element in the `Leaves' section''.
An empty ``Expression'' section (which implies that``Expression Length'' and ``Expression Depth'' both equal 0) has the special interpretation that every operator is a union.
As an example, the combination with expression and matrices as follows:
alpha | U | bravo | ) - ( | charlie | * | delta | )) - ( | delta | - | echo | ) |
I | Mb | Mc | I | Md | Me |
could be written out as:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
point | |
A | vector |
B | vector |
C | vector |
The A, B, and C vectors define a local coordinate system for the ellipsoid. The lengths of the vectors establish the three radii of the ellipsoid, each in the direction of its respective vector.
It is more storage-efficient, and less prone to tolerance errors, to
store spheres explicitly represented as a center point V and a radius
r.
Each number is stored in 8 bytes as double-precision IEEE floating point,
written in big-endian order, so the object body for this solid will
require ((1 * 3) + 1) * 8 = 32 bytes. The layout of Body_Data for
the sphere is
point | |
r | scalar |
The possible drawback to this change is that the vectors A, B, and C traditionally stored for the sphere are an explicit local coordinate system. This fact is used to aim existing spherical light sources, as the center of the beam of light is focused down the solid's -Z axis, which is transformed into the desired aim direction either via rotating the A, B, and C vectors or by transforming the local coordinate system of the solid with the homogeneous transform matrices in the arcs of the model DAG. It is not clear how this functionality could be preserved, except perhaps by making sure that light sources were explicitly modeled as ellipsoids rather than as spheres (perhaps with equal-length vectors). This would be something that an automatic database converter could guess at by looking for combinations with material type light and a single member that is an ellipsoid, but manual repairs would probably still be necessary.
In the v4 format, the ARB8 is stored as a base point V and seven vectors, making spatial translation computationally inexpensive. In the v5 format, the ARB8 will be stored as eight points in space to prevent values from mutating due to repeated vector addition and subtraction of V. The layout of Body_Data for the ARB8 is
point | |
P2 | point |
|
|
P8 | point |
VDOT(P,N) - d == 0 or VDOT(P,S) - S[3] == 0That is,
N[X]*x + N[Y]*y + N[Z]*z - d == 0 or S[X]*x + S[Y]*y + S[Z]*z - S[3] == 0The layout of Body_Data for the halfplane is
vector | |
d | scalar |
ARS, POLYSOLID, B-Spline Solid, ARBN Solid, PIPE/Wire Solid, Particle Solid, NMG Solid, TGC Solid (includes REC), Torus (TOR) Solid, Grip Pseudo-Solid (Leaf) and Joint Pseudo-Solid, Right Parabolic Cylinder (RPC), Right Hyperbolic Cylinder (RHC), Elliptical Paraboloid (EPA), Elliptical Hyperboloid (EHY), Elliptical Torus (ETO), Extruded Bitmap (EBM) Solid, Volumetric (VOL) Solid, Height-field (HF) Solid,
These TCL variables can be set by prior code execution (e.g., from commands given in MGED or from commands placed on the RT command line or in an RT animation script), as well as by TCL code included in the Header object(s)'s object-body field. In order to prevent long dependency chains between objects from being formed, only substitution of existing variables can be performed when an object is read -- formulas and procedure calls will not be permitted at substitution time. As a result, all variables will have been given values before any objects are retrieved from the database.
If variables depend on the values of other variables, then the user must take into account the order of assignment, just as with other types of programs.
Those binary numeric fields in the object that are to be substituted will be filled with an IEEE Signaling NaN pattern, to distinguish it from a valid binary number. Each object will need to have an additional variable-length field that will be used to hold the replacement variable list. Two possible strategies:
field_number=variable_name, field_number=variable_name,...After the object was imported into internal form, the indicated structure fields would be updated by de-referencing the corresponding variables. The Signaling NaNs would be used only for protection against software error.
In this proposal, two different interfaces will be required for reading objects from the database:
Some other function will be required to get and put the objects in an internal symbolic form. It might be wise to make this have semantics as close as possible to the form of Glenn Durfee's TCL MGED "db get" command. That is, the editable symbolic form should be an ASCII text string in a format suitable for further TCL processing. As get/put operations on the symbolic form will be quite rare relative to the operation to get the numeric form, the extra overhead of using an ASCII representation is negligible.
There would be a great consistency advantage to be gained if the symbolic substitutions could be handled by the same routines as the "db get" support. The "db get" routines are presently local to TCL MGED, but the "get" and "put" operations need to become standard function table interfaces to the g_xxx.c modules in LIBRT. This raises the related question of how bulky objects like NMGs, B-splines, and height fields should be represented in their ASCII forms.
String parameters, such as the optical shader parameter string, can be passed through the TCL interpreter if a left-square-bracket (''['') character is seen in the string. This would permit the normal TCL syntax to invoking the TCL interpreter to be used. In this example, the following two lines have the same effect:
plastic shine=[$shine] diffuse=[dfunc($statevar)] [plastic shine=$shine diffuse=dfunc($statevar)]
The tree walker should keep an auxiliary table that is indexed by database variable name. For each database variable that has been seen while walking the tree, there will be a list of db_full_path structures for every solid dependent on that variable, and a flag variable indicating whether the presently loaded version of each solid is out of date with respect to the variables on which it depends. (What data structure to use for the many-to-many mapping of variables to full paths?) The tree walker will automatically associate a TCL hooked function with each TCL variable on this list. Whenever a new value is assigned to a TCL variable, the dependent solids will be marked as out of date, but no other action will be taken.
Application code (TCL code or C code) will be able to call a library routine to "flush" the modifications, that is, to re-process all out-of-date solids to bring their internal representations (whether wireframes on an mged screen or prepped solids for raytracing) into sync with the variables on which they depend. It is envisioned that there will a library routine (db_variable_flush) that the application can call, providing a pointer to an application-provided function that will be called once with each out-of-date full path. In the case of mged, after processing each batch of input commands and events and before updating the screen, db_variable_flush would be called with a handler that essentially reruns the mged "e" command for each stale full path, so that the vlist would be regenerated before the screen update. As long as the number and complexity of the solids to be regenerated per screen update are modest, this will be highly interactive.
The simplest version of a TCL command to implement a Tk scale widget that would have this auto-update property would look something like this:
scale .sliders.f.kX -label "Change Variable ANTENNA_HEIGHT" \ -variable antenna_height \ -command "mged_variable_flush"
This might be accomplished in several ways:
Make the rtgeom.h-object-to-TCL conversion routines another access method for geometric objects. Question: How to convert nurbs, NMGs, HFs, etc.?
Perhaps export the C symbol for the rt_structparse table that corresponds to the rtgeom.h structure.
It would be nice if there were some way of "mounting" or "including" a subtree from a second ".g" file into the context of the current ".g" file, even if only on a read-only basis. Issues: name conflicts, ambiguity of names in full-path specs, multiple dbip in play for a "single" ".g" file, back/up references from the included subtree.
From: "David P. Kitzinger"Mike responds: The generalization of what you ask for are (a) some form of the selector node, and (b) the ability to direct LIBWDB to write geometry into the in-memory database, instead of into a disk file. The latter won't be any problem to provide, although it's only peripherally related to the new database format I'm hopeful that we'll implement that capability when we re-vamp LIBWDB to be aware of the new database. The former capability is something that I still don't have a good feel for. How complicated should the selection expression be? How many choices should be allowed? (two, or many?) Where do the variables come from that are used to make the selection?Subject: Re: Input Sought on V5 Database Format A couple of thoughts on the database format. First, ARA would like some resemblance of dynamically created geometry (geometry that gets introduced or turned on/off during an interrogation cycle). While we've talked about being able to update the database and perform incremental preps (which probably doesn't require database changes, just new routines to accomplish the aforesaid), it may be attractive to provide a mechanism whereby the client code can tell BRLCAD to ignore or turn off a piece of geometry. This would require an extra bit in the database for entities that BRLCAD code maintains.
Another perhaps minor feature that might be useful is the notion of database versions. Because a .g can be copied, the UNIX timestamp is not adequate to know which version of a .g file is most up to date. Also, if folks perform extra preprocessing on a .g file and save the data offboard in another file, the possibility for out-of-sync problems exist. It might be nice if the database could maintain a version number field for the entire database, perhaps along with a field for the login of the user making the last change. mged and/or libwdb routines would then increment the version number whenever alterations to the .g file occur, no matter how insignificant the change might be. mged could display this info when it first brings up the file, and an access routine could be provided to permit client code to check versions. This basically is revision control, but unburdens client code from trying to manage the same info off-board (since a modeler can always get into the .g and bypass any extra layers an application might wish to maintain, there is always risk when the application attempts to control this). Of course, if a modeler goes outside of BRLCAD, like cat'ing .g files together instead of using "concat", there may be problems but this should be rare. Perhaps having the database maintain a checksum for the .g would also catch even these problems.Mike responds: A version number could certainly be added, but I'm not sure how useful it would be. If user B copies a database from user A at revision level 42, and user A makes one more change (A has rev 43), and user B makes 3 changes (B has rev 45), how would the version number help, other than to indicate that things are mis-matched?
What is really needed is a better method for interfacing to RCS, which can deal with branches off the main path of development, and can even perform merges between two branches. I don't know how well RCS would work on binary databases. Perhaps if we could supply RCS a BRL-CAD-specific item-by-item comparison function....?
I'm certainly more familiar with the BRLCAD interrogation routines than actually constructing BRL-CAD models. Whenever certain operations occur, old data in the .g file is marked ID_FREE and left in place. Depending on the construction approach, this can leave rather large pockets that make the file large and artificially jack-up memory usage when interrogating. I solve this by converting to asc and then back to .g file to eliminate these pockets. Is there an existing mged command now that does basically the same thing?? Can the new database be designed to minimize/utilize these holes and/or can you provide routines/mged commands to "compact" the database?? Since you are going to an IEEE format g2asc will no longer be needed so my old approach will no longer work.Mike responds: The ID_FREE "pockets" are subject to re-use when the next database object is created. Also, they don't increase the amount of memory needed to hold the prepped database, although they do of course have to be read in so they can be skipped over. The worst-case (and very common) scenario in which these pockets can become quite plentiful is this:
+----+----+----+ | S1 | R... R | End +----+----+----+
+----+----+----+----+----+----+----+ | S1 | Hole | S2 | R........R | End +----+----+----+----+----+----+----+
+----+----+----+----+----+----+----+----+----+----+----+ | S1 | S3 |Hole| S2 | Hole....Hole | R..............R | End +----+----+----+----+----+----+----+----+----+----+----+
As for the second part of your suggestion, it would be very easy to add a command to MGED to compact out all the free granules. It could be implemented in two ways: in place, which would risk database damage if the system (or program) crashed while it was happening, and compaction by copying, which would risk running the disk out of space while operating, but would leave the original uncompacted file untouched in case of failure. I prefer #2. I propose the command name "compact".
Another question regards construction rules. mged allows me to construct a region by combining solids, other regions, and even groups with boolean operations. As far as I can tell this all seems to work fine, I've rendered some examples of such regions and they seemed correct, although warning messages are occasionally issued. Is this supposed to work? Is this a valid construction method? When I shoot a ray through a top level region, are lower pieces (groups and regions) treated as an integral part of the overall region (i.e. does the partition list reflect only the top level region?). Can this be clarified in the database format document or somewhere else? It obviously is a powerful method, so if you don't officially support some permutation of the above, would you consider it for the next release?Mike responds: being able to combine regions with other regions is supported -- the higher level region's material definition persists all the way down. This is particularly useful for being able to correct overlaps by subtracting off the offending region, rather than having to identify the precise solid that's overlapping.
Being able to boolean things from "upper level" combinations is also supported. In this case, a copy of the boolean operation is propagated downward to all affected regions, accumulating transformations as you would expect. This is especially nice for doing "cutaway views". Both of these things are features of the "new" tree walker in Release 4.
Keep up the good work, /| /--\ /| / | / | / | David P. Kitzinger /__| /___/ /__| Staff Scientist / | / | / | / | / | / | Applied Research Associates, Inc. (505) 883-3636 4300 San Mateo Blvd. NE, Suite A-220 (505) 883-3673 FAX Albuquerque, NM 87110 kitzinger@ara.com
From: John KeyserSubject: Comments on database v5 proposal - handling transformations. Date: Thu, 18 Jul 1996 11:20:15 -0400 (EDT) You spend some time in the version 5 proposal dealing with potential ways of handling the transformations for binary trees in the new database format. I thought of two other possibilities that might be possible, although they certainly have their drawbacks. For one, these methods might cause too much havoc with the "cleanness" of the data structures. Second, they might pose problems for backward compatibility. Also, they could cause the tree to be larger than desired, but probably not by too much. I am not familiar with animation scripts so I cannot say how they would be affected. The first solution would be to create transformation _nodes_ that are unary operators. This would allow you to represent the tree similar to the conceptual model of what is happening - a transformation node would separate an object from the combination. The in-memory model would be exactly as desired. This would mean having three types of nodes - primitive solids, combinations, and transformations. The second solution (and the one that seems better to me) would be to have a transformation _primitive_ defined. Thus, using the (A u B) - (C + D) example, a tree would look like: - / \ / \ / \ / \ / \ / \ / \ ? ? / \ / \ / \ / \ / \ / \ u M1 + M2 / \ / \ / \ / \ / \ / \ ? ? ? ? / \ / \ / \ / \ / \ / \ / \ / \ A Ma B Mb C Mc D Md Where the ? nodes could be any operation. One advantage of this would be that you could reference the same transformation matrix from several places (thus making it more certain that you were applying a consistent transform at several places in the tree). Both methods seem to handle "chains" of transformations (such as might occur when an arc is deleted) fine (transformations do not need to be combined). Also the idea of a "selector node" could be used to allow a user to change translations easily. Another big advantage would be that for identity matrices, nothing would need to be stored - no need for tolerancing. - John Keyser keyser@cs.unc.edu
The primary API for the database revolves around the routines rt_db_put_internal() and rt_db_get_internal(), plus the "internal" data structures vectored out from struct rt_db_internal: union tree for combinations, from "h/raytrace.h", and the family of struct rt_xxx_internal structures from "h/rtgeom.h".
The main issue for the database API becomes one of how a retrieved and "unwrapped" in-memory database object looks to an application. The most natural way would be to have a variable-length array of structures something like this:
struct attributes { char *aname; char type; long len; genptr_t value; } attrib[];where type would be either ASCII string, binary block, or binary integer (perhaps in several widths).
Then, to retrieve a BRL-CAD object (in external form) from the database, one would merely call:
db_get_external(ext, dp); db_unwrap_v5_external(atab, ext); id = db_get_integer_attribute( atab, "t" ); buf = db_get_block_attribute( atab, "b" );and then proceed with the BRL-CAD-level external-to-internal conversion from there.
The main questions are:
VIII. Appendix: Earlier Proposals for Database Organization
$Header: /vld/mike/public_html/papers/brlcad5.0/RCS/newdb.html,v 1.70
2000/06/30 15:07:48 jra Exp $
Collected by Mike Muuss
E-mail comments to mailto:acst@arl.mil