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.iModelId);
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 iTwin.js classes.
Root Subject
The following code:
const elementProps = iModel.elements.getElementProps(IModel.rootSubjectId);
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).toJSON();
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.createStartEnd(Angle.createDegrees(90), Angle.createDegrees(180));
const arc = Arc3d.createXY(center, radius, sweep);
const arcJson = 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.createPoints(points);
const lineStringJson = 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 = 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 = 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: 02 February, 2022