---
tags: pro3d, documentation, reporting
title: OPC Interface and Documentation
---
# OPC Specification
In this section we discuss our open file format *OPC*, standing for *O*rdered *P*oint *C*loud, to represent real-world surfaces in the form of 3D triangulated, hierarchical meshes. We discuss a single `opc`, how mulitple `opcs` form a `surface`, how `opcs` are made from `patches`, and how each `patch` holds its data enriched through `attributeMaps` and `textures`.
## OPC
An `opc` consists of a number of geometric patches and images that are arranged in a hierarchical fashion. An `opc` is a directory, that contains the subdirectories `patches/` and `images/`. `patches/` contains all patches as subdirectories, and `images/` contains all texture layers as subdirectories leading to the following file and folder structure:
```
guid-of-opc/
patches/
patchhierarchy.xml
guid-of-patch-1/
patch.xml
positions.aara
*.aara
...
guid-of-patch-N/
images/
name-of-texture-layer/
imagepyramid.xml
guid-of-image-1.tif
...
guid-of-image-N.tif
```
In `patches/` we find the `patchhierarchy.xml` that defines the hierarchical relationship between individual `patches` by specifying the sub-patches of each `patch` in the `patches/` directory. A `patchhierarchy.xml` may look like this:
```=xml
<?xml version="1.0" encoding="utf-8"?>
<Aardvark>
<PatchHierarchy>
<TagList/>
<AvgGeometrySizes>[0.466846581, 0.978991174, 1.705281181]</AvgGeometrySizes>
<RootPatch>02-Patch-00001~0011</RootPatch>
<SubPatchMap>
<item>
<key>01-Patch-00003~0009</key>
<val>
<nw>00-Patch-00005~0004</nw>
<ne>00-Patch-00007~0002</ne>
<sw>00-Patch-00008~0003</sw>
<se>00-Patch-00011~0006</se>
</val>
</item>
<item>
<key>01-Patch-00003~0010</key>
<val>
<nw>00-Patch-00005~0005</nw>
<ne>00-Patch-00006~0001</ne>
<sw>00-Patch-00009~0008</sw>
<se>00-Patch-00010~0007</se>
</val>
</item>
<item>
<key>02-Patch-00001~0011</key>
<val>
<nw>01-Patch-00003~0010</nw>
<sw>01-Patch-00003~0009</sw>
</val>
</item>
</SubPatchMap>
</PatchHierarchy>
</Aardvark>
```
The relation ship between `patches` and their sub`patches` is illustrated by the following figure:

And here we see the corresponding `opc` directory:
```
OPC_000_000/
patches/
patchhierarchy.xml
00-Patch-00005~0004/
00-Patch-00007~0002/
00-Patch-00008~0003/
00-Patch-00011~0006/
00-Patch-00005~0005/
00-Patch-00006~0001/
00-Patch-00009~0008/
00-Patch-00010~0007/
01-Patch-00003~0010/
01-Patch-00003~0009/
02-Patch-00001~0011/
images/
Image-0001/
```
## Surface
A `surface` is the product of an acquisition campaign. When laser-scanning a tunnel, a surface can be several kilometers long and represents the state of the tunnel's surface at a certain date and time, e.g. shotcrete in May 2019. In the case of remote sensing on Mars, a surface represents the reconstructed 3D surface originating from a distinct set of image captures originating from a set of PTU values. We combine `opcs` to form surfaces `surfaces` in the following folder structure:
```
name-of-surface/
name-of-surface.opcx
opcs/
guid-of-opc-1/
patches/
images/
guid-of-opc-2/
. . .
guid-of-opc-N/
```
## Patch
An OPC consists of a number of patches, where each patch has at least an array of 3d vertices, i.e. `positions.aara` and an array of texture coordinates, e.g. `DiffuseColor1Coordinates.aara`.
Additionally, it can have a number of per-vertex-attribute arrays, such as a slope map or a height map, as described in the *Attributes* section.
```=xml
<?xml version="1.0" encoding="utf-8"?>
<Aardvark>
<Patch>
<TagList/>
<PatchColRowOffset>0, 0</PatchColRowOffset>
<QuadVertexSortOrder>RowMajor</QuadVertexSortOrder>
<GeometryType>QuadList</GeometryType>
<Local2Global>
[[1.000000000, 0.000000000, 0.000000000, -2490132.229841444],
[0.000000000, 1.000000000, 0.000000000, 2285880.332404703],
[0.000000000, 0.000000000, 1.000000000, -271407.971937586],
[0.000000000, 0.000000000, 0.000000000, 1.000000000]]
</Local2Global>
<GlobalBoundingBox>
[[-2490132.357461989, 2285880.113015864, -271408.347052078], [-2490132.102220899, 2285880.552438436, -271407.596898737]]
</GlobalBoundingBox>
<LocalBoundingBox>
[[-0.127620545, -0.219388839, -0.375114492], [0.127620545, 0.220033733, 0.375038849]]
</LocalBoundingBox>
<Positions>Positions.aara</Positions>
<Attributes>
<Height_Map>Height_Map.aara</Height_Map>
</Attributes>
<Coordinates>
<DiffuseColor1Coordinates>Texture_Coordinates.aara</DiffuseColor1Coordinates>
</Coordinates>
<Textures>
<DiffuseColor1Texture>Texture\00-Tile-00106~0083.tif</DiffuseColor1Texture>
<DiffuseColor1Weights>Texture_Weights.aara</DiffuseColor1Weights>
</Textures>
</Patch>
</Aardvark>
```
The Xml Elements within the patch file define the various parts of a piece of geometry. Here is a breakdown of the elements, their use, and the necessary requirements they have to fulfill:
* **Aardvark**, **Patch**: the version attribute is optional, if it is not specified version=”0” is assumed
* **QuadVertexSortOrder**:
* **GeometryType**: one of the following strings: PointList, LineList, TriangleList, QuadList. If it is not specified, TriangleList is assumed.
* **Local2Global**: a single 4x4 matrix that specifies the origin and transformation of all the data of this patch with respect to the global coordinate system. In order to compute the global position of all vertices of the patch, its local coordinates (the ones stored in the Positions array) can be multiplied with this matrix.
* **GlobalBoundingBox**: the axis-aligned bounding box of the geometry of this patch in the global coordinate system. This can be used to decide which data to load before actually loading the data arrays. This is optional, however if it is not available, initial decisions on what to display can take significantly longer.
* **LocalBoundingBox**:
* **Positions**: if the Positions file contains a 2D-array of points, this implicitly defines a grid of quads. If the Positions file contains a 1D-array of points, the Indices array must be specified.
* **Textures**: these three structures specify all valid textures for the patch. Matching field names are used to define the association between texture, texture-coordinates, and texture projection camera:
* **DiffuseColorNTexture**: the field name of texture N in the Textures structure
* **Coordinates**:
* **DiffuseColorNCoordinates** (optional): the field name of the coordinates array for texture N in the Coordinates structure. This is only necessary if there is no camera specified for the corresponding texture.
Note: Additional field names in **Textures** or **Coordinates** can be defined as necessary .
## Attributes
```=xml
<?xml version="1.0"?>
<Aardvark version="4">
<SurfaceAttributes version="0" num="0">
<AttributeLayers num="1" count="6">
<AttributeLayer version="0" num="2">
<Type>Texture</Type>
<Label>Ortho</Label>
</AttributeLayer>
<AttributeLayer version="0" num="3">
<Type>Map</Type>
<Label>Height Map</Label>
<ChannelsActualRange>[-2509.1772460947, -1963.6514892573]</ChannelsActualRange>
<ChannelsDefinedRange>[-2540.7021484375, -1843.4295654297]</ChannelsDefinedRange>
</AttributeLayer>
<AttributeLayer version="0" num="4">
<Type>Map</Type>
<Label>Confidence</Label>
<ChannelsActualRange>[0, 15]</ChannelsActualRange>
<ChannelsDefinedRange>[0, 15]</ChannelsDefinedRange>
</AttributeLayer>
</AttributeLayers>
</SurfaceAttributes>
</Aardvark>
```
* **Aardvark**, **SurfaceAttributes**, **AttributeLayers** : the version attribute is optional, if it is not specified version=”0” is assumed
* **AttributeLayer**: Layer of extra information either in the form of per-vertex attribute maps or textures
* **Type**
* **Map**: Adds an attribute layer to a surface, so each vertex in a patch receives a value through this layer.
* **Texture**: Adds a texture layer to a surface, mapped via the respective coordinates array for each patch.
* **Label**: Name of the layer or texture as shown in PRo3D, which must also correspond the name of the directory the layer resides in.
* **ChannelsActualRange** The value range the data actually spans (min, max) in this particular surface.
* **ChannelsDefinedRange**: The value range the data can span (min, max). This allows to compare visual mappings, e.g. false coloring of height values, across multiple surfaces.
## Aardvark Array Files (\*.aara)
The Aardvark array file consists of 4 parts, stored in succession: the **Type**, the **Dimension**, the **Size**, and the **Data**. All primitive data types are stored in little-endian (Intel) format.
Type: a string specifying the data type, the string is stored by the string length as byte followed by the characters of the typename in UTF-8. Possible types are: `int`, `long`, `float`, `double`, `V2f`, `V3f`, `V2d`, `V3d`, `C3b`, `C3f`, `C4b`, `C4f`.
**Dimension**: the dimension of the data array, stored as a single byte. Possible values: **1, 2, 3**.
**Size**: the size of the data array, stored as 32-bit integer, separate in each dimension. As an example, if Dimension = 3, the size consists of 3 integers. The sizes are stored in the order as as follows, e.g. for a `V3f[10,20,30]`, the sizes `10, 20, 30` are stored in that order.
**Data**: the data elements (`int`, `long`, `double`, `V2f`, `V3f`, `V2d`, `V3d`, `C3b`, `C3f`, `C4b`, `C4f`) stored in binary format (IEEE for floats and doubles). The storage order of multiple dimensions is as follows: in the example of a `V3f[2,3,4]`, `2` planes of `3` lines of `4` `V3f`s are stored in the file without any separators. The graphic data types are defined as follows:
`V2f`: a 2D vector or point of two `float`s (x, y)
`V3f`: a 3D vector or point of three `float`s (x, y, z)
`V2d`: a 2D vector or point of two `double`s (x, y)
`V3d`: a 3D vector or point of three `double`s (x, y, z)
`C3b`: a color of 3 `byte`s (r, g, b)
`C3f`: a color of 3 `float`s (r, g, b)
`C4b`: a color of 4 `byte`s (r, g, b, a)
`C4f`: a color of 4 `float`s (r, g, b, a)
# PRo3D and OPCs
In the following we illustrate the functional integration of OPC data into the PRo3D Viewer. Clicking the menu icon in the upper left, selecting *Import\OPC* opens up a 'Select Folder' Dialog:

One can select multiple folders and does not have to care about the notion of a `surface` or an `opc`. PRo3D will 'crawl' through the selected folders, find `opc`s and interpret the containing folders as `surface`s.

A more detailed description about importing and handling `opc`s can be found in our manual at http://www.pro3d.space/docs/PRo3D_ShortUserManual.pdf
In order to display very large geoemtric scenes we must level-of-detail strategies in PRo3D. This requirment is the reason behind the hierarchical organization of patches in the `opc` file which lets us choose the right amount of detail for the current viewpoint.

# PRo3D Project Files (\*.pro3d)
With the third version of PRo3D, i.e. version numbers 3.\*.\*, we replaced the binary and rather inflexible scene files (\*.scn) with human readable \*.pro3d project files in a human readable JSON format. PRo3D project files are a bit long, will change over time, and in the end the individual elements are rather self explanatory. Nevertheless, we will discuss some aspects looking at a simplified \*.pro3d project file.
```=javascript
{
"bookmarks": { ... },
"cameraView": {
"view": [
"[0, 0, 1]",
"[6, 6, 6]",
"[-0.577350269189626, -0.577350269189626, -0.577350269189626]",
"[-0.408248290463863, -0.408248290463863, 0.816496580927726]",
"[-0.707106781186547, 0.707106781186547, 0]"
]
},
"config": {
"arrowLength": { ... },
"arrowThickness": { ... },
"depthOffset": { ... },
"dnsPlaneSize": { ... },
"drawOrientationCube": false,
"lodColoring": false,
"navigationSensitivity": { ... },
"nearPlane": { ... },
"farPlane": { ... },
"version": 1
},
"dockConfig": " ... layout string ... ",
"exploreCenter": "[0, 0, 0]",
"interactionMode": 0,
"navigationMode": 0,
"referenceSystem": { ... },
"surfaceModel": {
"surfaces": { ... },
}
"version": 0
}
```
The project file emcompasses the whole application state of PRo3D, including the last `cameraView` as well as the layout of the different tabs and windows save in `dockConfig`. Inside PRo3D there is a serialization component which writes the current application state to a `\*.pro3d` file and can also synthesize an exact application state from a `\*.pro3d` file with the help of Chiron (https://github.com/xyncro/chiron). With the fine-grained serialization of Chiron we could employ a versioning scheme allowing abitrary updates and backward compatibility for every type that has the `version` key.