Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix and improve handling of metadata semantics #325

Merged
merged 4 commits into from
Dec 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"@gltf-transform/core": "^3.2.1",
"@gltf-transform/extensions": "^3.2.1",
"@gltf-transform/functions": "^3.2.1",
"3d-tiles-tools": "0.4.2",
"3d-tiles-tools": "0.4.4",
"cesium": "^1.97.0",
"gltf-validator": "^2.0.0-dev.3.9",
"minimatch": "^5.1.0",
Expand Down
19 changes: 17 additions & 2 deletions specs/MetadataSchemaValidationSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -603,9 +603,17 @@ describe("Metadata schema validation", function () {
expect(result.get(0).type).toEqual("METADATA_SEMANTIC_INVALID");
});

it("detects issues in metadataClassPropertySemanticComponentTypeMismatch", async function () {
it("detects issues in metadataClassPropertySemanticComponentTypeMismatchA", async function () {
const result = await Validators.validateSchemaFile(
"specs/data/schemas/metadataClassPropertySemanticComponentTypeMismatch.json"
"specs/data/schemas/metadataClassPropertySemanticComponentTypeMismatchA.json"
);
expect(result.length).toEqual(1);
expect(result.get(0).type).toEqual("METADATA_SEMANTIC_INVALID");
});

it("detects issues in metadataClassPropertySemanticComponentTypeMismatchB", async function () {
const result = await Validators.validateSchemaFile(
"specs/data/schemas/metadataClassPropertySemanticComponentTypeMismatchB.json"
);
expect(result.length).toEqual(1);
expect(result.get(0).type).toEqual("METADATA_SEMANTIC_INVALID");
Expand All @@ -627,6 +635,13 @@ describe("Metadata schema validation", function () {
expect(result.get(0).type).toEqual("TYPE_MISMATCH");
});

it("detects no issues in metadataClassPropertySemanticGeneric", async function () {
const result = await Validators.validateSchemaFile(
"specs/data/schemas/metadataClassPropertySemanticGeneric.json"
);
expect(result.length).toEqual(0);
});

it("detects issues in metadataClassPropertySemanticNormalizedMismatch", async function () {
const result = await Validators.validateSchemaFile(
"specs/data/schemas/metadataClassPropertySemanticNormalizedMismatch.json"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"id": "EXAMPLE_ID",
"classes": {
"exampleClass": {
"properties": {
"exampleProperty": {
"type": "SCALAR",
"componentType": "INT32",
"array": true,
"semantic": "ATTRIBUTION_IDS"
}
}
}
}
}
14 changes: 14 additions & 0 deletions specs/data/schemas/metadataClassPropertySemanticGeneric.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"id": "EXAMPLE_ID",
"classes": {
"exampleClass": {
"properties": {
"exampleProperty": {
"type": "STRING",
"array": true,
"semantic": "ATTRIBUTION_STRINGS"
}
}
}
}
}
60 changes: 57 additions & 3 deletions src/validation/metadata/ClassPropertySemanticsValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class ClassPropertySemanticsValidator {
*
* @param metadataClassPath - The path for `ValidationIssue` instances
* @param properties - The properties of the schema class
* @param context - The `ValidatonContext`
* @param context - The `ValidationContext`
* @returns Whether the object was valid
*/
static validateSemantics(
Expand Down Expand Up @@ -233,6 +233,29 @@ export class ClassPropertySemanticsValidator {

return result;
}

/**
* Finds a "matcher" for the specified semantic in the given matching schema.
*
* The given semantic is just the name of the semantic. This is used property
* name in the matching schema. The classes in the given schema are searched
* for a property that has this (semantic) name. If such a "matching property"
* is found, it is returned, and used for checking if the property that
* contained the given semantic matches the "matching property".
*
* Ideally, comparing this "matching property" and the actual property should
* check whether the `type`, `component`, and `array` of the matching property
* are equal to these in the actual property. But given that semantics may
* have different `componentType` values, the returned property may define
* the `componentType` to be a RegEx that the actual component type must
* match against.
*
* Also see the comments for `createMatchingSchema`.
*
* @param matchingSchema - The matching metadata schema to search for semantics
* @param semantic - The name of the semantic
* @returns The matcher, or `undefined`
*/
private static findSemanticMatcher(
matchingSchema: any,
semantic: string
Expand Down Expand Up @@ -262,7 +285,7 @@ export class ClassPropertySemanticsValidator {
*
* Eventually, it might make sense to make the component types
* unambiguous, so that the semantics definition is actually
* a proper `Schema`. This could be achived by specific semantics
* a proper `Schema`. This could be achieved by specific semantics
* like `GEOMETRIC_ERROR_FLOAT32`.
*
* See https://github.com/CesiumGS/3d-tiles/issues/643
Expand All @@ -271,8 +294,39 @@ export class ClassPropertySemanticsValidator {
*/
private static createMatchingSchema() {
const matchingSchema = {
id: "CesiumMetadataSemantics-0.0.0",
id: "CesiumMetadataSemantics-0.0.1",
classes: {
GeneralSemantics: {
properties: {
ID: {
description: "The unique identifier for the entity.",
type: "STRING",
},
NAME: {
description:
"The name of the entity. Names should be human-readable, and do not have to be unique.",
type: "STRING",
},
DESCRIPTION: {
description:
"Description of the entity. Typically at least a phrase, and possibly several sentences or paragraphs.",
type: "STRING",
},
ATTRIBUTION_IDS: {
description:
"List of attribution IDs that index into a global list of attribution strings. This semantic may be assigned to metadata at any level of granularity including tileset, group, subtree, tile, content, feature, vertex, and texel granularity. The global list of attribution strings is located in a tileset or subtree with the property semantic ATTRIBUTION_STRINGS. The following precedence order is used to locate the attribution strings: first the containing subtree (if applicable), then the containing external tileset (if applicable), and finally the root tileset.",
type: "SCALAR",
array: true,
componentType: "UINT(8|16|32|64)",
},
ATTRIBUTION_STRINGS: {
description:
"List of attribution strings. Each string contains information about a data provider or copyright text. Text may include embedded markup languages such as HTML. This semantic may be assigned to metadata at any granularity (wherever STRING property values can be encoded). When used in combination with ATTRIBUTION_IDS it is assigned to subtrees and tilesets.",
type: "STRING",
array: true,
},
},
},
TilesetMetadataSemantics: {
properties: {
TILESET_FEATURE_ID_LABELS: {
Expand Down
2 changes: 1 addition & 1 deletion src/validation/metadata/MetadataClassValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class MetadataClassValidator {
* @param name - The name of the class
* @param metadataClass - The actual `MetadataClass`
* @param schema - The `Schema`
* @param context - The `ValidatonContext`
* @param context - The `ValidationContext`
* @returns Whether the object was valid
*/
static validateMetadataClass(
Expand Down
2 changes: 1 addition & 1 deletion src/validation/metadata/MetadataEnumValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class MetadataEnumValidator {
* @param metadataEnumPath - The path for `ValidationIssue` instances
* @param enumName - The name of the enum
* @param metadataEnum - The actual `MetadataEnum`
* @param context - The `ValidatonContext`
* @param context - The `ValidationContext`
* @returns Whether the object was valid
*/
static validateMetadataEnum(
Expand Down
2 changes: 1 addition & 1 deletion src/validation/metadata/SchemaDefinitionValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export class SchemaDefinitionValidator {
* @param name - A name for the containing object (usually 'tileset')
* @param schema - The `schema` object from the JSON
* @param schemaUri - The `schemaUri` from the JSON
* @param context - The `ValidatonContext`
* @param context - The `ValidationContext`
* @returns The schema definition validation result
*/
static async validateSchemaDefinition(
Expand Down
Loading