[x3d-public] X3D Ontology representation of enumerations... and MetadataSet information

Don Brutzman brutzman at nps.edu
Mon May 11 11:16:55 PDT 2020


1. Here are today's X3D Semantic Web working group weekly meeting minutes.

Attendees: Jakub Flotynski and Don Brutzman, with thanks to Anita Havele for zoom connectivity support.

[1.1] X3D Ontology for Semantic Web
       https://www.web3d.org/x3d/content/semantics/semantics.html

[1.2] Deployed X3D Ontology
       https://www.web3d.org/x3d/content/semantics/ontologies/X3dOntology4.0.ttl

[1.3] Version control
       https://sourceforge.net/p/x3d/code/HEAD/tree/www.web3d.org/semantics/ontologies

----------------------------

2. *Representing enumeration values*

We continued today and confirmed that the prior construct without wrapping "rdfs:domain [ ]" was OK... it looked like I got an intermittent/incorrect error from Protege previously.

Examples are slightly terser, not wrapping "rdfs:domain [ ]" around owl:oneOf and now read:

===========================================
:accessTypeChoices rdf:type rdfs:Datatype ;
   rdfs:label "accessTypeChoices" ;
   dc:description "accessTypeChoices are strictly allowed enumeration values for accessType, used when defining field declarations within a Script node or ProtoDeclare/ExternProtoDeclare statements" ;
   owl:oneOf ( 'initializeOnly' 'inputOnly' 'outputOnly' 'inputOutput' ) . # xs:NMTOKEN
# initializeOnly "A field with accessType initializeOnly can be initialized, but cannot send or receive events."
# inputOnly "A field with accessType inputOnly cannot be initialized or included in a scene file, but can receive input event values via a ROUTE."
# outputOnly "A field with accessType outputOnly cannot be initialized or included in a scene file, but can send output event values via a ROUTE."
# inputOutput "A field with accessType inputOutput can be initialized, and can also send or receive events."

:closureTypeChoices rdf:type rdfs:Datatype ;
   rdfs:label "closureTypeChoices" ;
   dc:description "closureTypeChoices are strictly allowed enumeration values for ArcClose2D closureType field" ;
   owl:oneOf ( 'PIE' 'CHORD' ) . # xs:NMTOKEN
# PIE "Connects arc endpoints to center, forming a pie wedge"
# CHORD "Connects arc endpoints directly to each other, as in chord on a circle"
# etc.
===========================================

However Jakub saw an error re-emerge, he is checking further before we check in this change.  Enumeration strings are tricky in OWL but worth the effort since strictness permits precise semantics regarding purpose.  We are being very careful with design refinements.

Interestingly, after a number of minutes, Protege indeed reported errors and turned property names red for all of today's questionable constructs.  (Perhaps this requires a reasoner or extra processing to determine that it is erroneous.)  So I will not check in the change.

Current published result, hopefully final:
===========================================
:accessTypeChoices rdf:type rdfs:Datatype ;
   rdfs:label "accessTypeChoices" ;
   dc:description "accessTypeChoices are strictly allowed enumeration values for accessType, used when defining field declarations within a Script node or ProtoDeclare/ExternProtoDeclare statements" ;
   rdfs:domain [ owl:oneOf ( 'initializeOnly' 'inputOnly' 'outputOnly' 'inputOutput' ) ] . # xs:NMTOKEN
# initializeOnly "A field with accessType initializeOnly can be initialized, but cannot send or receive events."
# inputOnly "A field with accessType inputOnly cannot be initialized or included in a scene file, but can receive input event values via a ROUTE."
# outputOnly "A field with accessType outputOnly cannot be initialized or included in a scene file, but can send output event values via a ROUTE."
# inputOutput "A field with accessType inputOutput can be initialized, and can also send or receive events."

:closureTypeChoices rdf:type rdfs:Datatype ;
   rdfs:label "closureTypeChoices" ;
   dc:description "closureTypeChoices are strictly allowed enumeration values for ArcClose2D closureType field" ;
   rdfs:domain [ owl:oneOf ( 'PIE' 'CHORD' ) ] . # xs:NMTOKEN
# PIE "Connects arc endpoints to center, forming a pie wedge"
# CHORD "Connects arc endpoints directly to each other, as in chord on a circle"
# etc.
===========================================

Recent changes to HAnimMotion frameCount and X3DUOM documentation are also applied, unit testing of SPARQL queries passes, have deployed latest X3D Ontology.

Next will run complete regression tests against all X3D examples as an extra check.

----------------------------

3. *Representing X3D Model Metadata*

Example of interest:

[3.1] X3D Example Archives: X3D for Web Authors, Chapter 15 Metadata, Metadata Node Examples
       https://x3dgraphics.com/examples/X3dForWebAuthors/Chapter15Metadata/MetadataNodeExamplesIndex.html
       https://x3dgraphics.com/examples/X3dForWebAuthors/Chapter15Metadata/MetadataNodeExamples.html
       https://x3dgraphics.com/examples/X3dForWebAuthors/Chapter15Metadata/MetadataNodeExamples.x3d
       https://x3dgraphics.com/examples/X3dForWebAuthors/Chapter15Metadata/MetadataNodeExamples.ttl

Excerpt:

     <!-- May 2017: X3D Specification clarification allows Metadata nodes at top level of Scene graph. -->
     <MetadataString name='TestRootMetadataNode' value='"Test satisfactory." "Note that all SFString values must be quoted."'/>
     <!-- Comments can appear between nodes (XML elements) but are not retained after a scene is parsed, loaded and playing -->

     <WorldInfo DEF='MyWorldInfo' info='"Metadata strings" "can go here" "as string array values"' title='MetadataNodeExamples.x3d Example Scene'>
       <!-- Structured information can go in Metadata nodes. Note that any X3D node can contain a single Metadata node with containerField='metadata' -->
       <MetadataSet DEF='MyMetadataSetNode' name='Metadata_name' reference='SomeReferenceStandard 1.2.3c'>
         <!-- MetadataSet can also contain multiple Metadata nodes with containerField='value' -->
         <MetadataBoolean DEF='MyMetadataBooleanNode' containerField='value' name='Coin Flip' reference='MetadataBoolean allowed in X3D v3.3 and later' value='true false true false'/>
         <MetadataDouble DEF='MyMetadataDoubleNode' containerField='value' name='Metadata_name' reference='SomeReferenceStandard 1.2.3c' value='3.141592658 2.71812181'/>
         <MetadataFloat DEF='MyMetadataFloatNode' containerField='value' name='Metadata_name' reference='SomeReferenceStandard 1.2.3c' value='9.8 6.023e+23'/>
         <MetadataInteger DEF='MyMetadataIntegerNode' containerField='value' name='Metadata_name' reference='SomeReferenceStandard 1.2.3c' value='6 28 496'/>
         <MetadataString DEF='MyMetadataStringNode' containerField='value' name='Metadata_name' reference='SomeReferenceStandard 1.2.3c' value='"Part 27" "P27" "p27"'/>
         <MetadataSet DEF='NestedMetadataSetNode' name='TestNestedMetadataSetNodes'>
           <MetadataString USE='MyMetadataStringNode' containerField='value'/>
           <MetadataInteger USE='MyMetadataIntegerNode' containerField='value'/>
           <MetadataFloat USE='MyMetadataFloatNode' containerField='value'/>
           <MetadataFloat containerField='value' name='coefficients' value='3.141592653 2.7128 1 0'/>
         </MetadataSet>
       </MetadataSet>
     </WorldInfo>

Corresponding translation into turtle, with autogeneration performed by X3dToTurtle.xslt stylesheet:

[3.2] X3dToTurtle.xslt conversion stylesheet translates an .x3d model from XML into .ttl triples
       https://www.web3d.org/x3d/stylesheets/X3dToTurtle.xslt

[3.3] X3D Example Archives: X3D for Web Authors, Chapter 15 Metadata, Metadata Node Examples: Turtle Syntax
       https://x3dgraphics.com/examples/X3dForWebAuthors/Chapter15Metadata/MetadataNodeExamples.ttl

:MetadataString_2_1 a owl:NamedIndividual, x3do:MetadataString ;
   x3do:hasParent :Scene ;
   x3do:name 'TestRootMetadataNode' ;
   x3do:value '"Test satisfactory." "Note that all SFString values must be quoted."' .
:MyWorldInfo a owl:NamedIndividual, x3do:WorldInfo ;
   x3do:hasParent :Scene ;
   x3do:hasMetadata :MyMetadataSetNode ;
   x3do:info '"Metadata strings" "can go here" "as string array values"' ;
   x3do:title 'MetadataNodeExamples.x3d Example Scene' .
:MyMetadataSetNode a owl:NamedIndividual, x3do:MetadataSet ;
   x3do:hasParent :MyWorldInfo ;
   x3do:hasValue :MyMetadataBooleanNode, :MyMetadataDoubleNode, :MyMetadataFloatNode, :MyMetadataIntegerNode, :MyMetadataStringNode ;
   x3do:hasMetadata :NestedMetadataSetNode ;
   x3do:name 'Metadata_name' ;
   x3do:reference 'SomeReferenceStandard 1.2.3c' .
:MyMetadataBooleanNode a owl:NamedIndividual, x3do:MetadataBoolean ;
   x3do:hasParent :MyMetadataSetNode ;
   x3do:name 'Coin Flip' ;
   x3do:reference 'MetadataBoolean allowed in X3D v3.3 and later' ;
   x3do:value ( true false true false ) .
:MyMetadataDoubleNode a owl:NamedIndividual, x3do:MetadataDouble ;
   x3do:hasParent :MyMetadataSetNode ;
   x3do:name 'Metadata_name' ;
   x3do:reference 'SomeReferenceStandard 1.2.3c' ;
   x3do:value ( 3.141592658 2.71812181 ) .
:MyMetadataFloatNode a owl:NamedIndividual, x3do:MetadataFloat ;
   x3do:hasParent :MyMetadataSetNode ;
   x3do:name 'Metadata_name' ;
   x3do:reference 'SomeReferenceStandard 1.2.3c' ;
   x3do:value ( 9.8 6.023e+23 ) .
:MyMetadataIntegerNode a owl:NamedIndividual, x3do:MetadataInteger ;
   x3do:hasParent :MyMetadataSetNode ;
   x3do:name 'Metadata_name' ;
   x3do:reference 'SomeReferenceStandard 1.2.3c' ;
   x3do:value ( 6 28 496 ) .
:MyMetadataStringNode a owl:NamedIndividual, x3do:MetadataString ;
   x3do:hasParent :MyMetadataSetNode ;
   x3do:name 'Metadata_name' ;
   x3do:reference 'SomeReferenceStandard 1.2.3c' ;
   x3do:value '"Part 27" "P27" "p27"' .
:NestedMetadataSetNode a owl:NamedIndividual, x3do:MetadataSet ;
   x3do:hasParent :MyMetadataSetNode ;
   x3do:hasValue :MyMetadataStringNode-USE-1, :MyMetadataIntegerNode-USE-1, :MyMetadataFloatNode-USE-1, :MetadataFloat_2_2_1_6_4 ;
   x3do:name 'TestNestedMetadataSetNodes' .
:MyMetadataStringNode-USE-1 a owl:NamedIndividual, x3do:MetadataString ;
   x3do:hasParent :NestedMetadataSetNode ;
   owl:sameAs :MyMetadataStringNode . # DEF matching this USE
:MyMetadataIntegerNode-USE-1 a owl:NamedIndividual, x3do:MetadataInteger ;
   x3do:hasParent :NestedMetadataSetNode ;
   owl:sameAs :MyMetadataIntegerNode . # DEF matching this USE
:MyMetadataFloatNode-USE-1 a owl:NamedIndividual, x3do:MetadataFloat ;
   x3do:hasParent :NestedMetadataSetNode ;
   owl:sameAs :MyMetadataFloatNode . # DEF matching this USE
:MetadataFloat_2_2_1_6_4 a owl:NamedIndividual, x3do:MetadataFloat ;
   x3do:hasParent :NestedMetadataSetNode ;
   x3do:name 'coefficients' ;
   x3do:value ( 3.141592653 2.7128 1 0 ) .

Note that, in addition to identical name/value pairs, parent-child relationships are described via the x3do:hasParent relationship.  Parent nodes are referred to via labels matching DEF, sequence of a USE node, or (not shown here) for non-DEF non-USE nodes, unique labels reflecting node name and position in scene graph.

So it would certainly seem that we have a satisfactory representation of X3D MetadataSet information in Turtle, easily repeatable (numerous examples autogenerated already), and our next step is to show SPARQL queries against examples that tease out the name=value pairs.

Similarly we should write SPARQL queries against head/meta information in an X3D model.

(drum roll...) At that point we have general query capabilities for X3D ontology.  Getting closer...

We will look at each of these for next week.  Have fun with X3D Semantic Web!  8)

v/r Don and Jakub

----------------------------


On 5/5/2020 12:00 AM, Don Brutzman wrote:
> 
> 
> On 5/4/2020 10:06 AM, Don Brutzman wrote:
>> X3D Semantic Web working group meeting, 4 May 2020.
>>
>> Attendees: Jakub Flotyński, John Carlson, Don Brutzman.
>>
>> Jakub had improvements to the following representation of enumeration types from X3DUOM in X3D Ontology.
>>
>> On 4/26/2020 11:32 PM, Don Brutzman wrote:
>>> -------
>>>
>>> c. X3D Ontology
>>> https://www.web3d.org/x3d/content/semantics/semantics.html
>>> - simple-type enumeration lists added, excerpt follows
>>> - typing of fields now reflects these simple types
>>> - name attribute typing is also stricter, e.g. some names are NMTOKEN
>>> - found feature in protege for diagnosing error lines in turtle .ttl
>>> - ready for further work on accessType representations, continuing prior efforts
>>>
>>> :closureTypeChoices rdf:type rdfs:Datatype ;
>>>    rdfs:label "closureTypeChoices" ;
>>>    dc:description "closureTypeChoices are strictly allowed enumeration values for ArcClose2D closureType field" ;
>>>    rdfs:range xs:NMTOKEN ;
>>>    rdfs:domain [ owl:unionOf ( 'PIE' 'CHORD' ) ] .
>>> # PIE "Connects arc endpoints to center, forming a pie wedge"
>>> # CHORD "Connects arc endpoints directly to each other, as in chord on a circle"
>>
>> References:
>>
>> * https://www.w3.org/TR/owl-ref/#EnumeratedDatatype
> note superceded, more below
> 
>> Important note in recommendation regarding lists:
>>
>>> NOTE: Enumerated datatypes are not part of OWL Lite. 
>>
>> We should document the X3D Ontology correspondingly.  We are striving for correctness and completeness so this is not considered a limitation.
> 
> When we look at the revised references below, such a restriction is not called out via NOTE.
> 
> Rather than haphazard documentation, have not added this superceded note.
> 
> When the X3D Ontology appears fully robust, an analysis of various version levels will be more appropriate.
> 
>> Next. As design patterns, please look at the next two excerpts.
>>
>> * https://github.com/w3c/omn/blob/master/omnlib/import/owl.ttl
>>
>> [line 88] (Jakub will check further on whether this is the final version)
>>
>>> owl:DataRange
>>>
>>>     a rdfs:Class ;
>>>
>>>     rdfs:comment "The class of OWL data ranges, which are special kinds of datatypes. Note: The use of the IRI owl:DataRange has been deprecated as of OWL 2. The IRI rdfs:Datatype SHOULD be used instead." ;
>>>
>>>     rdfs:isDefinedBy <http://www.w3.org/2002/07/owl#> ;
>>>
>>>     rdfs:label "DataRange" ;
>>>
>>>     rdfs:subClassOf rdfs:Datatype .
>>
>> [line 493]
>>
>>> owl:oneOf
>>>
>>>     a rdf:Property ;
>>>
>>>     rdfs:comment "The property that determines the collection of individuals or data values that build an enumeration." ;
>>>
>>>     rdfs:domain rdfs:Class ;
>>>
>>>     rdfs:isDefinedBy <http://www.w3.org/2002/07/owl#> ;
>>>
>>>     rdfs:label "oneOf" ;
>>>
>>>     rdfs:range rdf:List .
> 
> Here is a head start, Jakub.  Updated references:
> 
> [1] OWL 2 Web Ontology Language
>      Document Overview (Second Edition)
>      W3C Recommendation 11 December 2012
>      https://www.w3.org/TR/owl2-overview
> 
> [2] OWL 2 Web Ontology Language
>      Quick Reference Guide (Second Edition)
>      W3C Recommendation 11 December 2012
>      2.4 Data Ranges
>      https://www.w3.org/TR/2012/REC-owl2-quick-reference-20121211/#Data_Ranges
> 
> Data Range Expressions
> 
> Language Feature    Functional Syntax    RDF Syntax
> [...]
> literal enumeration    DataOneOf(v1 … vn)    _:x rdf:type rdfs:Datatype.
>                          _:x owl:oneOf ( v1 … vn ).
> 
>> This leads us to a new pattern:
>> ====================================
>> :accessTypeChoices rdf:type rdfs:Datatype ;
>>      owl:oneOf ( 'initializeOnly' 'inputOnly' 'outputOnly' 'inputOutput' ).
>>
>> :accessType rdfs:range :accessTypeChoices.
>> ====================================
> 
> this pattern still looks good with respect to the preceding specification prose.
> 
>> Jakub will check latest-greatest W3C Recommendation, Don will apply this pattern in X3D Ontology.  This pattern will pertain to all of the enumeration Choices listed in the ontology.
> 
> i have applied the pattern but it does NOT pass Protege.  Offending construct:
> 
>      owl:oneOf ( 'initializeOnly' 'inputOnly' 'outputOnly' 'inputOutput' ) .
> 
> Troubleshooting by inspection, made it closer to prior form by wrapping rdfs:domain [ ] as follows:
> 
>      rdfs:domain [ owl:oneOf ( 'initializeOnly' 'inputOnly' 'outputOnly' 'inputOutput' ) ] .
> 
> This revised pattern passed Protege checks.  Actual change summary is pretty minimal: "owl:unionOf" modified as "owl:oneOf".
> 
> Please confirm.  Examples of new forms:
> ======================
> 
> :accessTypeChoices rdf:type rdfs:Datatype ;
>    rdfs:label "accessTypeChoices" ;
>    dc:description "accessTypeChoices are strictly allowed enumeration values for accessType, used when defining field declarations within a Script/ProtoDeclare/ExternProtoDeclare" ;
>    rdfs:domain [ owl:oneOf ( 'initializeOnly' 'inputOnly' 'outputOnly' 'inputOutput' ) ] .
> # initializeOnly "A field with accessType initializeOnly can be initialized, but cannot send or receive events."
> # inputOnly "A field with accessType inputOnly cannot be initialized or included in a scene file, but can receive input event values via a ROUTE."
> # outputOnly "A field with accessType outputOnly cannot be initialized or included in a scene file, but can send output event values via a ROUTE."
> # inputOutput "A field with accessType inputOutput can be initialized, and can also send or receive events."
> 
> ======================
> 
> :closureTypeChoices rdf:type rdfs:Datatype ;
>    rdfs:label "closureTypeChoices" ;
>    dc:description "closureTypeChoices are strictly allowed enumeration values for ArcClose2D closureType field" ;
>    rdfs:domain [ owl:oneOf ( 'PIE' 'CHORD' ) ] .
> # PIE "Connects arc endpoints to center, forming a pie wedge"
> # CHORD "Connects arc endpoints directly to each other, as in chord on a circle"
> 
> ======================
> 
> Jakub am I reading the Recommendation incorrectly?  Seems sensible to put "rdfs:domain [ ]" there, so perhaps we should report an erratum for W3C?
> 
> Also found the following warnings in the Protege log, apparently harmless but we should scrutinize further.  Looking at the OwlDoc for revised ontology,
> 
>     WARN  21:54:12  Illegal redeclarations of entities: reuse of entity http://www.web3d.org/specifications/X3dOntology4.0#IS in punning not allowed [DataProperty: IS, Class: IS]
>     WARN  21:54:12  Annotation property domain axiom turned to data property domain after parsing. This could introduce errors if the original domain was an anonymous expression: _:genid-nodeid-node1e7hiubeex2842 is the new domain.
>     WARN  21:54:12  Annotation property domain axiom turned to data property domain after parsing. This could introduce errors if the original domain was an anonymous expression: _:genid-nodeid-node1e7hiubeex2882 is the new domain.
>     WARN  21:54:12  Annotation property domain axiom turned to data property domain after parsing. This could introduce errors if the original domain was an anonymous expression: _:genid-nodeid-node1e7hiubeex2814 is the new domain.
>     WARN  21:54:12  Annotation property domain axiom turned to data property domain after parsing. This could introduce errors if the original domain was an anonymous expression: _:genid-nodeid-node1e7hiubeex2808 is the new domain.
>     WARN  21:54:12  Annotation property domain axiom turned to data property domain after parsing. This could introduce errors if the original domain was an anonymous expression: _:genid-nodeid-node1e7hiubeex1824 is the new domain.
>     WARN  21:54:12  Annotation property domain axiom turned to data property domain after parsing. This could introduce errors if the original domain was an anonymous expression: _:genid-nodeid-node1e7hiubeex1228 is the new domain.
>     WARN  21:54:12  Annotation property domain axiom turned to data property domain after parsing. This could introduce errors if the original domain was an anonymous expression: _:genid-nodeid-node1e7hiubeex1149 is the new domain.
>     WARN  21:54:12  Annotation property domain axiom turned to data property domain after parsing. This could introduce errors if the original domain was an anonymous expression: _:genid-nodeid-node1e7hiubeex2820 is the new domain.
>     WARN  21:54:12  Annotation property domain axiom turned to data property domain after parsing. This could introduce errors if the original domain was an anonymous expression: _:genid-nodeid-node1e7hiubeex1526 is the new domain.

p.s. we were unable to diagnose what caused this, the "blank nodes" (term for unlabeled triples) seemed to hold no information and indeed appeared blank when inspected.


>> Assuming that works, we will again look at adding accessType information to every field definition in the X3D Ontology.
> 
> still pending discussion
> 
>> Also of interest: enumeration "Values" that are not restrictive but rather optional and extendible values.  I will use same pattern, we will continue scrutinizing these relationships.
>>
>> ================================================
>> :fontFamilyValues rdf:type rdfs:Datatype ;
>>    rdfs:label "fontFamilyValues" ;
>>    dc:description "fontFamilyValues are allowed enumeration values for FontStyle/ScreenFontStyle node family field" ;
>>    rdfs:range :MFString ;
>>    rdfs:domain [ owl:unionOf ( '"SANS"' '"SERIF"' '"TYPEWRITER"' ) ] .
>> # "SANS" "default font family for sans-serif font such as Helvetica"
>> # "SERIF" "default font family for serif font such as Times-Roman"
>> # "TYPEWRITER" "default font family for a fixed-pitch font such as Courier"
>> ================================================
> 
> revised:
> 
> :fontFamilyValues rdf:type rdfs:Datatype ;
>    rdfs:label "fontFamilyValues" ;
>    dc:description "fontFamilyValues are supported enumeration values for FontStyle/ScreenFontStyle node family field" ;
>    owl:oneOf [ '"SANS"' '"SERIF"' '"TYPEWRITER"' ] .
> # "SANS" "default font family for sans-serif font such as Helvetica"
> # "SERIF" "default font family for serif font such as Times-Roman"
> # "TYPEWRITER" "default font family for a fixed-pitch font such as Courier"
> 
> currently have the same structures defined for the datatype itself but probably should relax the use of that datatype, falling back to baseType instead.  this would avoid false validation warnings while allowing a semantic rule to see if alternate values were utilized... OK accomplished that, wherever appropriate the supported value SimpleType is listed in a comment instead.
> 
> example showing both forms, FontStyle family and justify:
> 
> :FontStyle a owl:Class ;
>    rdfs:subClassOf :X3DFontStyleNode ;
>    rdfs:label "FontStyle is an X3DFontStyleNode that defines the size, family, justification, and other styles used by Text nodes." .
> :family a owl:DatatypeProperty ;
>    rdfs:domain :FontStyle ;
>    rdfs:range :MFString . # alternate enumerations allowed, supported values found in fontFamilyValues
> :horizontal a owl:DatatypeProperty ;
>    rdfs:domain :FontStyle ;
>    rdfs:range :SFBool .
> :justify a owl:DatatypeProperty ;
>    rdfs:domain :FontStyle ;
>    rdfs:range :justifyChoices .
> 
>> Future follow-on work:
> 
> a. Confirm enumerations representations, write a SPARQL query or two.
> b. adding accessType information to every field definition in the X3D Ontology
> c. SPARQL patterns for X3D event-routing chains: first listing correct chains, then diagnosing malformed event chains.
> d. HAnim representations of parent-child relationships for HAnimJoint, HAnimSegment and HAnimSite.
>>
>> Thanks (as ever) for steady progress today.  Have fun with X3D Ontology!   8)
> 
> Today's changes committed and deployed.
> 
> [3] X3D Ontology for Semantic Web
>      https://www.web3d.org/x3d/content/semantics
> 
> all the best, Don

all the best, Don
-- 
Don Brutzman  Naval Postgraduate School, Code USW/Br       brutzman at nps.edu
Watkins 270,  MOVES Institute, Monterey CA 93943-5000 USA   +1.831.656.2149
X3D graphics, virtual worlds, navy robotics http://faculty.nps.edu/brutzman



More information about the x3d-public mailing list