Wire Format

The wire format describes the way entities are serialized to JSON.

Here is some sample code that dumps the entire iModel to JSON.

/**
 * This example code shows one possible way to dump an iModel to JSON.
 * The strategy employed by this example is as follows:
 * - Use the GUID of the iModel to create a new directory
 * - Create a JSON file per Model under that directory
 * - Output a JSON string and newline character per Element into the Model JSON file
 *
 * > Note: The Model JSON file is formatted in such a way that it can either be loaded as JSON or optionally read line-by-line to conserve memory.
 */
class DumpIModel {
  public static dump(iModel: IModelDb, baseDir: string): void {
    // Use the GUID of the iModel to create a new directory
    const outputDir = path.join(baseDir, iModel.getGuid().toString());
    if (!fs.existsSync(outputDir)) {
      fs.mkdirSync(outputDir);
    }
    // Iterate each Model
    const sql = `SELECT ECInstanceId AS id FROM ${Model.classFullName}`;
    iModel.withPreparedStatement(sql, (statement: ECSqlStatement) => {
      while (DbResult.BE_SQLITE_ROW === statement.step()) {
        const row = statement.getRow();
        DumpIModel.dumpModel(iModel, row.id, outputDir);
      }
    });
  }

  private static dumpModel(iModel: IModelDb, modelId: Id64String, outputDir: string): void {
    // Use the Id of the Model to create a JSON output file
    const outputFile = path.join(outputDir, `${modelId.toString()}.json`);
    fs.writeFileSync(outputFile, "[");
    // ECSQL to SELECT every Element in the specified Model
    const sql = `SELECT ECInstanceId AS id FROM ${Element.classFullName} WHERE Model.Id=:modelId`;
    iModel.withPreparedStatement(sql, (statement: ECSqlStatement) => {
      statement.bindId("modelId", modelId);
      let isFirstEntry = true;
      while (DbResult.BE_SQLITE_ROW === statement.step()) {
        isFirstEntry ? fs.appendFileSync(outputFile, "\n") : fs.appendFileSync(outputFile, ",\n");
        isFirstEntry = false;
        const row = statement.getRow();
        // Get the ElementProps (including the geometry detail) for the specified Element
        const elementProps = iModel.elements.getElementProps({ id: row.id, wantGeometry: true });
        // Output the ElementProps as a JSON string
        fs.appendFileSync(outputFile, JSON.stringify(elementProps));
      }
    });
    fs.appendFileSync(outputFile, "\n]");
  }
}

Below are examples of wire formats for a few interesting iModel.js classes.

Root Subject

The following code:

    const elementProps = iModel.elements.getElementProps(IModel.rootSubjectId) as ElementProps;
    const json = JSON.stringify(elementProps, undefined, 2);

Produces the following result:

{
  "classFullName": "BisCore:Subject",
  "code": {
    "scope": "0x1",
    "spec": "0x1f",
    "value": "DgnDbTestUtils"
  },
  "description": "",
  "id": "0x1",
  "model": "0x1"
}

RepositoryModel

The following code:

    const modelProps = iModel.models.getModel(IModel.repositoryModelId) as ModelProps;
    const json = JSON.stringify(modelProps, undefined, 2);

Produces the following result:

{
  "classFullName": "BisCore:RepositoryModel",
  "id": "0x1",
  "isPrivate": false,
  "isTemplate": false,
  "jsonProperties": {},
  "modeledElement": {
    "id": "0x1",
    "relClassName": "BisCore:ModelModelsElement"
  },
  "parentModel": "0x1",
  "name": "DgnDbTestUtils"
}

GeometricElement3d

The following code produces JSON at various stages on the way to creating a GeometricElement3d:

    // Construct an Arc3d (local coordinates)
    const center = new Point3d(0, 0, 0);
    const radius = 1;
    const sweep: AngleSweep = AngleSweep.createStartEnd(Angle.createDegrees(90), Angle.createDegrees(180));
    const arc: Arc3d = Arc3d.createXY(center, radius, sweep);
    const arcJson: string = JSON.stringify(arc, undefined, 2);

    // Construct a LineString3d (local coordinates)
    const points: Point3d[] = [
      new Point3d(0, 0, 0),
      new Point3d(1, 2, 0),
      new Point3d(1, 2, 4),
    ];
    const lineString: LineString3d = LineString3d.createPoints(points);
    const lineStringJson: string = JSON.stringify(lineString, undefined, 2);

    // Construct a GeometryStream containing the Arc3d and LineString3d created above (local coordinates)
    const builder = new GeometryStreamBuilder();
    builder.appendGeometry(arc);
    builder.appendGeometry(lineString);
    const geometryStreamJson: string = JSON.stringify(builder.geometryStream, undefined, 2);

    // Construct a Placement (world coordinates)
    const origin = new Point3d(100, 100, 0);
    const angles = YawPitchRollAngles.createDegrees(0, 90, 0);
    const placement: Placement3dProps = { origin, angles };
    const placementJson: string = JSON.stringify(placement, undefined, 2);

    // Construct a GeometricElement3d using the GeometryStream and Placement created above
    const elementProps: GeometricElement3dProps = {
      classFullName: "Generic:PhysicalObject",
      model: modelId,
      code: Code.createEmpty(),
      category: categoryId,
      placement,
      geom: builder.geometryStream,
    };
    const elementPropsJson: string = JSON.stringify(elementProps, undefined, 2);

Arc3d JSON

Below is the JSON from the Arc3d:

{
  "center": [
    0,
    0,
    0
  ],
  "sweep": [
    90,
    180
  ],
  "vector0": [
    1,
    0,
    0
  ],
  "vector90": [
    0,
    1,
    0
  ]
}

LineString3d JSON

Below is the JSON from the LineString3d:

[
  [
    0,
    0,
    0
  ],
  [
    1,
    2,
    0
  ],
  [
    1,
    2,
    4
  ]
]

GeometryStream JSON

Below is the JSON from the GeometryStream that contains the Arc3d and LineString3d that were previously created. This shows that a GeometryStream is just an array of entries:

[
  {
    "arc": {
      "center": [
        0,
        0,
        0
      ],
      "vectorX": [
        1,
        0,
        0
      ],
      "vectorY": [
        0,
        1,
        0
      ],
      "sweepStartEnd": [
        90,
        180
      ]
    }
  },
  {
    "lineString": [
      [
        0,
        0,
        0
      ],
      [
        1,
        2,
        0
      ],
      [
        1,
        2,
        4
      ]
    ]
  }
]

Placement3d JSON

Below is the JSON from the Placement3d that will be used to place the GeometryStream in world coordinates:

{
  "origin": [
    100,
    100,
    0
  ],
  "angles": {
    "pitch": 90
  }
}

GeometricElement3d JSON

Below is the JSON from the GeometricElement3d. This shows that the JSON from the GeometricElement3d contains the JSON from the objects used to create it:

{
  "classFullName": "Generic:PhysicalObject",
  "model": "0",
  "code": {
    "spec": "0x1",
    "scope": "0x1",
    "value": ""
  },
  "category": "0",
  "placement": {
    "origin": [
      100,
      100,
      0
    ],
    "angles": {
      "pitch": 90
    }
  },
  "geom": [
    {
      "arc": {
        "center": [
          0,
          0,
          0
        ],
        "vectorX": [
          1,
          0,
          0
        ],
        "vectorY": [
          0,
          1,
          0
        ],
        "sweepStartEnd": [
          90,
          180
        ]
      }
    },
    {
      "lineString": [
        [
          0,
          0,
          0
        ],
        [
          1,
          2,
          0
        ],
        [
          1,
          2,
          4
        ]
      ]
    }
  ]
}

Last Updated: 06 December, 2018