[x3d-public] Building an X3D Object Model - step 3

Roy Walmsley roy.walmsley at ntlworld.com
Sat Oct 21 06:10:52 PDT 2017


Hi,

 

We're nearly ready to move on to nodes, we just need to extend our list of
fields that we have defined. Before we do that, we'll  start with a reminder
of where we got to last time, by listing the things we have defined.

 

enum SAIFieldAccess {

    initializeOnly,

    inputOnly,

    outputOnly,

    inputOutput

};

 

enum SAIFieldType {

    SFBool,

    MFBool,

    SFColor,

   .

};

 

X3DField {

    enum SAIFieldType type;

    enum SAIFieldAccess accessType;

    SAIFieldName name;

 

    enum SAIFieldAccess getAccessType (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_DISPOSED;

    enum SAIFieldType getType (void) throws SAI_CONNECTION_ERROR,
SAI_DISPOSED;

    SAIFieldName getName (void) throws SAI_CONNECTION_ERROR, SAI_DISPOSED;

    void addInterest (SAIRequester requester) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INSUFFICIENT_CAPABILITIES, SAI_NODE_IN_USE, SAI_DISPOSED;

    void removeInterest (SAIRequester requester) throws
SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INSUFFICIENT_CAPABILITIES, SAI_NODE_IN_USE, SAI_DISPOSED;

    void dispose void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING;

};

 

X3DArrayField : X3DField {

    int getNum (void) throws throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void removeAllValues (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

    void removeValue (int index) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;

};

 

SFInt32 : X3DField {

    int32 value = 0;

 

    int32 getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void setValue (int32 newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

};

 

MFInt32 : X3DArrayField {

    int32 value[];

 

    int32[] getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    int32 get1Value (int index) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;

    void appendValue (int32 newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

    void insertValue (int index, int32 newValue) throws
SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;

    void setValue (int32 newValue[]) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

    void set1Value (int index, int32 newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;

};

 

We need to define some additional field types. We need SFNode, and SFString.
These can be done analogously to SFInt32, with a change to the data type.
For SFNode the data type is SAINode. This is defined in ISO/IEC 19775-2:2015
clause 5.2.22 as "an identifier for a node.". The data type for string, as
we have already seen is SAIString.

Reference:
http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/dataRef.ht
ml#SAINode

 

For our object model definitions for  SFNode and SFString we also need to
modify the default values. These are listed in ISO/IEC 19775-1:2013 clause 5
Field type reference. Clause 5.3.12 SFNode and MFNode details the default
value of an uninitialized SFNode field to be NULL, while clause 5.3.14
SFString and MFString specifies that the default value of an uninitialized
SFString field is the empty string.

Reference:
http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/fieldsDef.
html#SFNodeAndMFNode

Reference:
http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/fieldsDef.
html#SFStringAndMFString

 

So our two additional field type definitions become:

 

SFNode : X3DField {

    SAINode value = NULL;

 

    SAINode getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void setValue (SAINode newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

};

 

SFString : X3DField {

    SAIString value = "";

 

    SAIString getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void setValue (SAIString newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

};

 

Now we can move on to nodes! We'll use the same processes that we did for
fields. We started that with reviewing the characteristics listed in ISO/IEC
19775-1:2013 clause 4.4.2.1 Overview.

Reference:
http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/concepts.h
tml#ObjectmodelOverview

Listing these characteristics we have:

1.	A type name
2.	Zero or more field values
3.	Zero or more events it can receive and send
4.	A name

 

Considering 3) more carefully, we see that actually events are sent and
received from the fields within a node, and not the nodes themselves. So
we'll save that for later.

 

Referring back to the second paragraph in clause 4.4.2.1 we note that ".
nodes and are derived from the X3DNode
<http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/component
s/core.html#X3DNode>  object.". So that is the base object that we must
define. We have two characteristics, type name and node, that are common to
all nodes. So our starter definition is:

 

X3DNode {

    type;

    name;

};

 

Now we need to look at the node signature for X3DNode. This is found at
ISO/IEC 19775-1:2013 clause 7.3.5 X3DNode. We see that it has a single
SFNode field, named "metadata". That field has an access type of
"inputOutput", and a default value of "NULL". Furthermore, the "metadata"
field only accepts nodes that inherit the X3DMetadataObject interface.
However, again we'll save this last requirement about acceptable node types
for later.

Reference:
http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components
/core.html#X3DNode

 

Now we can expand the definition of X3DNode to include the "metadata" field.
It becomes:

 

X3DNode {

    type;

    name;

    SFNode metadata ("metadata", inputOutput, NULL);

};

 

Notice that we have used "metadata" twice. The first occurrence provides a
property name that software engineers can use to refer to this particular
field within the codes. The second occurrence is there to provide the name
for the name property in the field. Similarly, the "inputOutput" specifies
the access type, and the "NULL" the default value. You'll notice that this
looks remarkably like a constructor. And we have not defined any
constructors in our field definitions. We need to fix that. However, since
these constructors have default values, they need to go into the individual
classes. So, we'll extend our four specific field types to include a
constructor.

 

SFInt32 : X3DField {

    int32 value = 0;

 

    int32 getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void setValue (int32 newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

 

    SFInt32 (SAIFieldName fieldName, enum SAIFieldAccess accessType, int32
defaultValue);

};

 

MFInt32 : X3DArrayField {

    int32 value[];

 

    int32[] getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    int32 get1Value (int index) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;

    void appendValue (int32 newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

    void insertValue (int index, int32 newValue) throws
SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;

    void setValue (int32 newValue[]) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

    void set1Value (int index, int32 newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;

 

    MFInt32 (SAIFieldName fieldName, enum SAIFieldAccess accessType, int32
defaultValue[]);

};

 

SFNode : X3DField {

    SAINode value = NULL;

 

    SAINode getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void setValue (SAINode newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

 

    SFNode (SAIFieldName fieldName, enum SAIFieldAccess accessType, SAINode
defaultValue);

};

 

SFString : X3DField {

    SAIString value = "";

 

    SAIString getValue (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void setValue (SAIString newValue) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

 

    SFString (SAIFieldName fieldName, enum SAIFieldAccess accessType,
SAIString defaultValue);

};

 

Of course, our base abstract types X3DField and X3DArrayField will also need
constructors, so we could add those too.

 

X3DField {

    enum SAIFieldType type;

    enum SAIFieldAccess accessType;

    SAIFieldName name;

 

    enum SAIFieldAccess getAccessType (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_DISPOSED;

    enum SAIFieldType getType (void) throws SAI_CONNECTION_ERROR,
SAI_DISPOSED;

    SAIFieldName getName (void) throws SAI_CONNECTION_ERROR, SAI_DISPOSED;

    void addInterest (SAIRequester requester) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INSUFFICIENT_CAPABILITIES, SAI_NODE_IN_USE, SAI_DISPOSED;

    void removeInterest (SAIRequester requester) throws
SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE,
SAI_INSUFFICIENT_CAPABILITIES, SAI_NODE_IN_USE, SAI_DISPOSED;

    void dispose void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING;

 

    X3DField (SAIFieldName fieldName, enum SAIFieldAccess accessType);

};

 

X3DArrayField : X3DField {

    int getNum (void) throws throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_DISPOSED;

    void removeAllValues (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_DISPOSED;

    void removeValue (int index) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_ACCESS_TYPE, SAI_IMPORTED_NODE,
SAI_INVALID_ARRAY_INDEX, SAI_DISPOSED;

 

    X3DArrayField (void);

};

 

Now we can go back to our X3DNode definition. We need to review the
requirements of the SAI from ISO/IEC 19775-2:2015. Looking at clause 5 Data
type reference we are going to need one additional data type, namely
SAINodeType. This is defined in clause 5.2.23 SAINodeType. It represents the
type of the node. We can proceed like we did for SAIFieldType, and define an
enumeration. Here's how it will look:

Reference:
http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/dataRef.ht
ml#SAINodeType

 

enum SAINodeType {

    Anchor,

    Appearance,

    Arc2D,

    ..

};

 

With all the data types known we can add these to our X3DNode definition.

 

X3DNode {

    enum SAINodeType  type;

    ??? name;

    SFNode metadata ("metadata", inputOutput, NULL);

};

 

And suddenly we come across our next problem. There is no data type for the
node name. We had one for the field, namely SAIFieldName. But then the names
of nodes are handled differently, as it is the "DEF" name. And so the node
name has the standard SAIString data type, as can be seen from reviewing
clause 6.4.10 namedNodeHandling. So the X3DNode definition becomes:

Reference:
http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/servRef.ht
ml#NamedNodeHandling

 

X3DNode {

    enum SAINodeType  type;

    SAIString name;

    SFNode metadata ("metadata", inputOutput, NULL);

};

 

Now we need to look at the node services defined in clause 6.6 Node
services, just like we did for Field services. With the benefit of that
experience, we can skip all the workings, and jump straight to the results.
And now we see we have confused ourselves. We need to "names". One is a
"type name", and the other is the "DEF name". Both have the data type
SAIString. So, when we fix that, and add our services in, plus a
constructor, our X3DNode definition becomes:

Reference:
http://www.web3d.org/documents/specifications/19775-2/V3.3/Part02/servRef.ht
ml#NodeServices

 

X3DNode {

    enum SAINodeType  type;

    SAIString DEFname;

    SAIString typeName;

    SFNode metadata ("metadata", inputOutput, NULL);

 

    SAIString getTypeName (void) throws SAI_CONNECTION_ERROR, SAI_DISPOSED;

    enum SAINodeType getType (void) throws SAI_CONNECTION_ERROR,
SAI_DISPOSED;

    SAIField getField (SAIFieldName fieldname) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING, SAI_INVALID_NAME, SAI_DISPOSED;

    static SAIField[] getFieldDefinitions (enum SAINodeType nodeType) throws
SAI_CONNECTION_ERROR, SAI_INVALID_OPERATION_TIMING, SAI_INVALID_NAME,
SAI_DISPOSED;

    void dispose (void) throws SAI_CONNECTION_ERROR,
SAI_INVALID_OPERATION_TIMING;

 

    protected X3DNode (void);

};

 

You will note that I have prepended the getFieldDefinitions method with the
qualifier "static". This indicates that this method has no dependence on any
particular instance, but is a generic function that can be called even in
the absence of any instances. However, this also raises the question about
the validity of some of the error exceptions that can be thrown. I have also
added the qualifier "protected" to the constructor for X3DNode. This
indicates that this constructor can only be called by interfaces that
inherit this definition, and not by other code. This prevents the
instantiation of an abstract object type.

 

Problem 6: Since the node service "getFieldDefinitions" is independent of
any instances, the exceptions "SAI_INVALID_OPERATION_TIMING" and
"SAI_DISPOSED" are inappropriate, and should be removed.

 

Finally, we can define a concrete node. Let's choose MetadataInteger, since
we have the fields for that. First, though, we have to define the interface
"X3DMetadataObject". This just contains two fields. Again, for the time
being we'll ignore the fact that the "name" field is required, saving it for
later. The definition then becomes:

 

X3DMetadataObject {

    SFString name ("name", inputOutput, "");

    SFString reference ("reference", inputOutput, "");

 

    protected X3DMetadataObject (void);

};

 

Finally, we can define MetadataInteger, as follows:

 

MetadataInteger : X3DNode, X3DMetadataObject {

    MFInt32 value ("value, inputOutput, int32[]);

 

    MetadataInteger (void);

};

 

That's it for this session. Tomorrow, we'll take a step back, and look at
the implications of what we have defined so far, reviewing it from the
perspective of different language bindings, and automatic code generation.

 

All the best,

 

Roy

 

 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://web3d.org/pipermail/x3d-public_web3d.org/attachments/20171021/c31242c6/attachment-0001.html>


More information about the x3d-public mailing list