diff --git a/examples/vehicle_example/vehicle_example.xoma b/examples/vehicle_example/vehicle_example.xoma index 60116c96..1361269d 100644 --- a/examples/vehicle_example/vehicle_example.xoma +++ b/examples/vehicle_example/vehicle_example.xoma @@ -14,6 +14,30 @@ "validationDescription": "Since this is a fictional vehicle, the geometry was not validated. Standard compliance was verified manually.", "assetType": "object", "objectClass": "vehicle", + "vehicleClassData": { + "vehicleCategory": "car", + "performance": { + "maxSpeed": 41.67, + "maxAcceleration": 8.0, + "maxDeceleration": 8.0 + }, + "axles": { + "frontAxle": { + "maxSteering": 0.175, + "wheelDiameter": 0.661, + "trackWidth": 1.318, + "positionX": 1.254, + "positionZ": 0.33 + }, + "rearAxle": { + "maxSteering": 0.0, + "wheelDiameter": 0.661, + "trackWidth": 1.318, + "positionX": -1.146, + "positionZ": 0.33 + } + } + }, "animated": false, "pbrMaterialWorkflow": "metallic", "triangleCount": 50760, diff --git a/schemas/asset_schema.json b/schemas/asset_schema.json index f1918dd1..ce5a1185 100644 --- a/schemas/asset_schema.json +++ b/schemas/asset_schema.json @@ -2,6 +2,46 @@ "$schema": "http://json-schema.org/draft-07/schema#", "type": "object", "description": "ASAM OpenMATERIAL 3D Geometry Asset file definition.", + "definitions": { + "Axle": { + "type": "object", + "description": "The definition of vehicle axle. based on the https://releases.asam.net/OpenSCENARIO/1.0.0/Model-Documentation/content/Axle.html[OpenSCENARIO vehicle axle definition].", + "properties": { + "maxSteering": { + "type": "number", + "description": "Maximum steering angle which can be performed by the wheels on this axle. Unit: rad; Range: [0;PI], symmetrical.", + "minimum": 0, + "maximum": 3.14159 + }, + "wheelDiameter": { + "type": "number", + "description": "Diameter of the wheels on this axle. Unit: meter; Range: ]0..inf[.", + "exclusiveMinimum": 0 + }, + "trackWidth": { + "type": "number", + "description": "Distance of the wheels center lines at zero steering. Unit: meter; Range: [0..inf[.", + "minimum": 0 + }, + "positionX": { + "type": "number", + "description": "Longitudinal position of the axle with respect to the vehicles center of the bounding box projected to the ground. Unit: meter; Range: [0..inf[." + }, + "positionZ": { + "type": "number", + "description": "Z-position of the axle with respect to the vehicles center of the bounding box projected to the ground. Usually this is half of wheel diameter. Unit:meter; Range:[0..inf[.", + "minimum": 0 + } + }, + "required": [ + "maxSteering", + "wheelDiameter", + "trackWidth", + "positionX", + "positionZ" + ] + } + }, "properties": { "metadata": { "type": "object", @@ -77,6 +117,59 @@ "other" ] }, + "vehicleClassData": { + "type": "object", + "description": "Vehicle specific data. This SHALL be filled if 'objectClass' is 'vehicle' based on the https://releases.asam.net/OpenSCENARIO/1.0.0/Model-Documentation/content/Axle.html[OpenSCENARIO vehicle definition].", + "properties": { + "vehicleCategory": { + "type": "string", + "description": "Type of the vehicle.", + "enum": ["car", "van", "truck", "trailer", "semitrailer", "bus", "motorbike", "bicycle", "train", "tram"] + }, + "performance": { + "type": "object", + "description": "Performance values of a vehicle.", + "properties": { + "maxSpeed": { + "type": "number", + "description": "Maximum speed of the vehicle. Unit: meter/second." + }, + "maxAcceleration": { + "type": "number", + "description": "Maximum acceleration of the vehicle. Unit: meter/second^2. Range: [0..inf[.", + "minimum": 0 + }, + "maxDeceleration": { + "type": "number", + "description": "Maximum deceleration of the vehicle. Unit: meter/second^2. Range: [0..inf[.", + "minimum": 0 + } + }, + "required": ["maxSpeed", "maxAcceleration", "maxDeceleration"] + }, + "axles": { + "type": "object", + "description": "A set of the axles of a vehicle. A vehicle must have a front axle and a rear axle. It might have additional axles.", + "properties": { + "frontAxle": { + "$ref": "#/definitions/Axle", + "description": "Details about the front axle." + }, + "rearAxle": { + "$ref": "#/definitions/Axle", + "description": "Details about the rear axle." + }, + "additionalAxles": { + "type": "array", + "description": "An optional array of additional axles with the same properties as frontAxle and rearAxle.", + "items": {"$ref": "#/definitions/Axle"} + } + }, + "required": ["frontAxle", "rearAxle"] + } + }, + "required": ["vehicleCategory", "performance", "axles"] + }, "animated": { "type": "boolean", "description": "Indicates whether the 3D model contains keyframe animations." diff --git a/scripts/json2asciidoc.py b/scripts/json2asciidoc.py index d1106123..43cdfaca 100644 --- a/scripts/json2asciidoc.py +++ b/scripts/json2asciidoc.py @@ -1,5 +1,6 @@ import os import json +import copy import argparse from typing import List, Dict @@ -124,6 +125,7 @@ def generate_asciidoc_main_field(field_name: str, schema: Dict, is_required: boo Args: field_name (str): The name of the field to generate documentation for. schema (dict): The JSON schema dictionary. + is_required (bool): True if the field is required required_fields (list): List of required fields for the specified field. Returns: @@ -159,16 +161,62 @@ def generate_asciidoc_main_field(field_name: str, schema: Dict, is_required: boo return asciidoc_content +def resolve_references(definitions, schema): + """ + Resolve JSON Schema references in the provided schema using the given definitions. + + This function recursively traverses the input schema, replacing `$ref` fields with their corresponding + definitions from the `definitions` dictionary. It supports nested objects and arrays, ensuring that + all references within the schema are resolved. The function also preserves additional fields in objects + containing `$ref`. + + Args: + definitions (dict): A dictionary containing schema definitions, where keys are the definition names + and values are the corresponding schema fragments. + schema (dict or list): The JSON schema to process. This can be an object, an array, or any other valid + JSON structure. + + Returns: + dict or list: The schema with all `$ref` references resolved. + + Note: + - If a `$ref` cannot be resolved (e.g., the referenced key is missing from `definitions`), the function + leaves the `$ref` field untouched. + - Circular references are not handled and may cause infinite recursion. + """ + if isinstance(schema, dict): + if "$ref" in schema: + ref = schema["$ref"] + if ref.startswith("#/definitions/"): + definition_key = ref.split("/")[-1] + if definition_key in definitions: + resolved_def = copy.deepcopy(definitions[definition_key]) + # Include other fields in the original object + schema.pop("$ref") + schema.update(resolved_def) + else: + # Recursively resolve other fields + for key, value in schema.items(): + schema[key] = resolve_references(definitions, value) + elif isinstance(schema, list): + schema = [resolve_references(definitions, item) for item in schema] + return schema + + def generate_asciidoc_file(json_schema_path: str, output_path: str): """ Generate AsciiDoc file for the given JSON schema. Args: json_schema_path (str): Path to the json schema. + output_path: (str): Path to write the ASCIIdoc file to. """ with open(json_schema_path, 'r') as file: schema = json.load(file) + definitions = schema.get("definitions", {}) + schema = resolve_references(definitions, schema) + base_filename = os.path.basename(json_schema_path).replace('_', '-') headline = format_main_headline(os.path.splitext(base_filename)[0]) asciidoc_content = f"= {headline}\n\n"