Task 700: .SUR File Format
Task 700: .SUR File Format
1. List of all the properties of this file format intrinsic to its file system
Based on the .SUR file format specification from 3D-XplorMath (a text-based format for parametric surfaces):
- File Identifier: A string "SurfaceDataFile" to identify the file type.
- Version Number: An integer indicating the format version (e.g., 3).
- U Resolution: An integer representing the number of samples along the u parametric coordinate.
- V Resolution: An integer representing the number of samples along the v parametric coordinate.
- Number of Tiles: An integer indicating the number of tiles (max 32).
- Camera Position: A 3D vector (x, y, z floats) for the camera viewpoint.
- View Direction: A 3D vector (x, y, z floats) for the camera view direction.
- Image Plane Center: A 3D vector (x, y, z floats) for the center of the image plane.
- Image Plane Horizontal Vector: A 3D vector (x, y, z floats) for the horizontal direction of the image plane.
- Image Plane Vertical Vector: A 3D vector (x, y, z floats) for the vertical direction of the image plane.
- Focal Length: A float representing the focal length.
- Scale: A float representing the graphic scale.
- Eye Separation: A float for stereoscopic eye separation.
- Clipping Plane Distance: A float for the clipping plane distance.
- Vertex Grid: A grid of 3D points (u_resolution * v_resolution points, each with x, y, z floats).
- Tile Transformation Matrices: 4x3 matrices (floats) for each tile if number of tiles > 1.
- Normal Correctors: Integers (1 or -1) for each tile.
2. Two direct download links for files of format .SUR
- https://paulbourke.net/dataformats/sur/cyclide.surf.gz (a gzipped .sur file example from the format description)
- https://rucore.libraries.rutgers.edu/rutgers-lib/39190/ZIP/1/ (a ZIP containing multiple .sur files; direct .sur files were hard to find, so this is the closest with multiple .sur inside)
3. Ghost blog embedded HTML JavaScript for drag and drop .SUR file dump
Drag and Drop .SUR File
Drop .SUR file here
4. Python class for .SUR file
class SURFile:
def __init__(self, filename):
self.filename = filename
self.properties = {}
def read(self):
with open(self.filename, 'r') as f:
lines = f.read().strip().split('\n')
index = 0
self.properties['File Identifier'] = lines[index].strip()
index += 1
self.properties['Version Number'] = int(lines[index])
index += 1
self.properties['U Resolution'] = int(lines[index])
index += 1
self.properties['V Resolution'] = int(lines[index])
index += 1
self.properties['Number of Tiles'] = int(lines[index])
index += 1
if self.properties['Version Number'] >= 2:
self.properties['Camera Position'] = [float(lines[index + i]) for i in range(3)]
index += 3
self.properties['View Direction'] = [float(lines[index + i]) for i in range(3)]
index += 3
self.properties['Image Plane Center'] = [float(lines[index + i]) for i in range(3)]
index += 3
self.properties['Image Plane Horizontal Vector'] = [float(lines[index + i]) for i in range(3)]
index += 3
self.properties['Image Plane Vertical Vector'] = [float(lines[index + i]) for i in range(3)]
index += 3
self.properties['Focal Length'] = float(lines[index])
index += 1
self.properties['Scale'] = float(lines[index])
index += 1
self.properties['Eye Separation'] = float(lines[index])
index += 1
self.properties['Clipping Plane Distance'] = float(lines[index])
index += 1
self.properties['Vertex Grid'] = []
for _ in range(self.properties['U Resolution']):
row = []
for _ in range(self.properties['V Resolution']):
row.append([float(lines[index + i]) for i in range(3)])
index += 3
self.properties['Vertex Grid'].push(row)
self.properties['Tile Transformation Matrices'] = []
if self.properties['Number of Tiles'] > 1:
for _ in range(self.properties['Number of Tiles']):
matrix = []
for _ in range(4):
row = [float(lines[index + i]) for i in range(3)]
matrix.append(row)
index += 3
self.properties['Tile Transformation Matrices'].append(matrix)
self.properties['Normal Correctors'] = []
for _ in range(self.properties['Number of Tiles']):
self.properties['Normal Correctors'].append(int(lines[index]))
index += 1
def print_properties(self):
import json
print(json.dumps(self.properties, indent=4))
def write(self, filename):
with open(filename, 'w') as f:
f.write('SurfaceDataFile\n')
f.write(f"{self.properties['Version Number']}\n")
f.write(f"{self.properties['U Resolution']}\n")
f.write(f"{self.properties['V Resolution']}\n")
f.write(f"{self.properties['Number of Tiles']}\n")
if self.properties['Version Number'] >= 2:
for key in ['Camera Position', 'View Direction', 'Image Plane Center', 'Image Plane Horizontal Vector', 'Image Plane Vertical Vector']:
for val in self.properties[key]:
f.write(f"{val}\n")
for key in ['Focal Length', 'Scale', 'Eye Separation', 'Clipping Plane Distance']:
f.write(f"{self.properties[key]}\n")
for row in self.properties['Vertex Grid']:
for point in row:
for val in point:
f.write(f"{val}\n")
if self.properties['Number of Tiles'] > 1:
for matrix in self.properties['Tile Transformation Matrices']:
for row in matrix:
for val in row:
f.write(f"{val}\n")
for val in self.properties['Normal Correctors']:
f.write(f"{val}\n")
# Example usage
# sur = SURFile('example.sur')
# sur.read()
# sur.print_properties()
# sur.write('output.sur')
5. Java class for .SUR file
import java.io.*;
import java.util.*;
public class SURFile {
private String filename;
private Map<String, Object> properties = new HashMap<>();
public SURFile(String filename) {
this.filename = filename;
}
public void read() throws IOException {
List<String> lines = new ArrayList<>();
try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
String line;
while ( (line = br.readLine()) != null) {
lines.add(line.trim());
}
}
int index = 0;
properties.put("File Identifier", lines.get(index++));
properties.put("Version Number", Integer.parseInt(lines.get(index++)));
properties.put("U Resolution", Integer.parseInt(lines.get(index++)));
properties.put("V Resolution", Integer.parseInt(lines.get(index++)));
properties.put("Number of Tiles", Integer.parseInt(lines.get(index++)));
int version = (int) properties.get("Version Number");
if (version >= 2) {
double[] cameraPos = new double[3];
for (int i = 0; i < 3; i++) cameraPos[i] = Double.parseDouble(lines.get(index++));
properties.put("Camera Position", cameraPos);
double[] viewDir = new double[3];
for (int i = 0; i < 3; i++) viewDir[i] = Double.parseDouble(lines.get(index++));
properties.put("View Direction", viewDir);
double[] imageCenter = new double[3];
for (int i = 0; i < 3; i++) imageCenter[i] = Double.parseDouble(lines.get(index++));
properties.put("Image Plane Center", imageCenter);
double[] horizVec = new double[3];
for (int i = 0; i < 3; i++) horizVec[i] = Double.parseDouble(lines.get(index++));
properties.put("Image Plane Horizontal Vector", horizVec);
double[] vertVec = new double[3];
for (int i = 0; i < 3; i++) vertVec[i] = Double.parseDouble(lines.get(index++));
properties.put("Image Plane Vertical Vector", vertVec);
properties.put("Focal Length", Double.parseDouble(lines.get(index++)));
properties.put("Scale", Double.parseDouble(lines.get(index++)));
properties.put("Eye Separation", Double.parseDouble(lines.get(index++)));
properties.put("Clipping Plane Distance", Double.parseDouble(lines.get(index++)));
}
int uRes = (int) properties.get("U Resolution");
int vRes = (int) properties.get("V Resolution");
double[][][] vertexGrid = new double[uRes][vRes][3];
for (int i = 0; i < uRes; i++) {
for (int j = 0; j < vRes; j++) {
for (int k = 0; k < 3; k++) {
vertexGrid[i][j][k] = Double.parseDouble(lines.get(index++));
}
}
}
properties.put("Vertex Grid", vertexGrid);
int numTiles = (int) properties.get("Number of Tiles");
if (numTiles > 1) {
double[][][][] matrices = new double[numTiles][4][3][1]; // Simplified
for (int k = 0; k < numTiles; k++) {
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 3; col++) {
matrices[k][row][col][0] = Double.parseDouble(lines.get(index++));
}
}
}
properties.put("Tile Transformation Matrices", matrices);
}
int[] normalCorrectors = new int[numTiles];
for (int k = 0; k < numTiles; k++) {
normalCorrectors[k] = Integer.parseInt(lines.get(index++));
}
properties.put("Normal Correctors", normalCorrectors);
}
public void printProperties() {
System.out.println(properties);
}
public void write(String filename) throws IOException {
try (PrintWriter pw = new PrintWriter(new File(filename))) {
pw.println("SurfaceDataFile");
pw.println(properties.get("Version Number"));
pw.println(properties.get("U Resolution"));
pw.println(properties.get("V Resolution"));
pw.println(properties.get("Number of Tiles"));
int version = (int) properties.get("Version Number");
if (version >= 2) {
double[] arr = (double[]) properties.get("Camera Position");
for (double val : arr) pw.println(val);
arr = (double[]) properties.get("View Direction");
for (double val : arr) pw.println(val);
arr = (double[]) properties.get("Image Plane Center");
for (double val : arr) pw.println(val);
arr = (double[]) properties.get("Image Plane Horizontal Vector");
for (double val : arr) pw.println(val);
arr = (double[]) properties.get("Image Plane Vertical Vector");
for (double val : arr) pw.println(val);
pw.println(properties.get("Focal Length"));
pw.println(properties.get("Scale"));
pw.println(properties.get("Eye Separation"));
pw.println(properties.get("Clipping Plane Distance"));
}
double[][][] vertexGrid = (double[][][]) properties.get("Vertex Grid");
for (double[][] row : vertexGrid) {
for (double[] point : row) {
for (double val : point) pw.println(val);
}
}
int numTiles = (int) properties.get("Number of Tiles");
if (numTiles > 1) {
double[][][][] matrices = (double[][][][]) properties.get("Tile Transformation Matrices");
for (double[][][] matrix : matrices) {
for (double[][] row : matrix) {
for (double[] col : row) {
pw.println(col[0]);
}
}
}
}
int[] normalCorrectors = (int[]) properties.get("Normal Correctors");
for (int val : normalCorrectors) pw.println(val);
}
}
// Example usage
// public static void main(String[] args) throws IOException {
// SURFile sur = new SURFile("example.sur");
// sur.read();
// sur.printProperties();
// sur.write("output.sur");
// }
}
6. JavaScript class for .SUR file
class SURFile {
constructor(filename) {
this.filename = filename;
this.properties = {};
}
async read() {
const response = await fetch(this.filename);
const text = await response.text();
const lines = text.trim().split(/\r?\n/);
let index = 0;
this.properties['File Identifier'] = lines[index++].trim();
this.properties['Version Number'] = parseInt(lines[index++]);
this.properties['U Resolution'] = parseInt(lines[index++]);
this.properties['V Resolution'] = parseInt(lines[index++]);
this.properties['Number of Tiles'] = parseInt(lines[index++]);
if (this.properties['Version Number'] >= 2) {
this.properties['Camera Position'] = [parseFloat(lines[index++]), parseFloat(lines[index++]), parseFloat(lines[index++])];
this.properties['View Direction'] = [parseFloat(lines[index++]), parseFloat(lines[index++]), parseFloat(lines[index++])];
this.properties['Image Plane Center'] = [parseFloat(lines[index++]), parseFloat(lines[index++]), parseFloat(lines[index++])];
this.properties['Image Plane Horizontal Vector'] = [parseFloat(lines[index++]), parseFloat(lines[index++]), parseFloat(lines[index++])];
this.properties['Image Plane Vertical Vector'] = [parseFloat(lines[index++]), parseFloat(lines[index++]), parseFloat(lines[index++])];
this.properties['Focal Length'] = parseFloat(lines[index++]);
this.properties['Scale'] = parseFloat(lines[index++]);
this.properties['Eye Separation'] = parseFloat(lines[index++]);
this.properties['Clipping Plane Distance'] = parseFloat(lines[index++]);
}
this.properties['Vertex Grid'] = [];
for (let i = 0; i < this.properties['U Resolution']; i++) {
const row = [];
for (let j = 0; j < this.properties['V Resolution']; j++) {
row.push([parseFloat(lines[index++]), parseFloat(lines[index++]), parseFloat(lines[index++])]);
}
this.properties['Vertex Grid'].push(row);
}
this.properties['Tile Transformation Matrices'] = [];
if (this.properties['Number of Tiles'] > 1) {
for (let k = 0; k < this.properties['Number of Tiles']; k++) {
const matrix = [];
for (let row = 0; row < 4; row++) {
const rowData = [];
for (let col = 0; col < 3; col++) {
rowData.push(parseFloat(lines[index++]));
}
matrix.push(rowData);
}
this.properties['Tile Transformation Matrices'].push(matrix);
}
}
this.properties['Normal Correctors'] = [];
for (let k = 0; k < this.properties['Number of Tiles']; k++) {
this.properties['Normal Correctors'].push(parseInt(lines[index++]));
}
}
printProperties() {
console.log(JSON.stringify(this.properties, null, 2));
}
async write(filename) {
let content = 'SurfaceDataFile\n';
content += this.properties['Version Number'] + '\n';
content += this.properties['U Resolution'] + '\n';
content += this.properties['V Resolution'] + '\n';
content += this.properties['Number of Tiles'] + '\n';
if (this.properties['Version Number'] >= 2) {
['Camera Position', 'View Direction', 'Image Plane Center', 'Image Plane Horizontal Vector', 'Image Plane Vertical Vector'].forEach(key => {
this.properties[key].forEach(val => content += val + '\n');
});
['Focal Length', 'Scale', 'Eye Separation', 'Clipping Plane Distance'].forEach(key => {
content += this.properties[key] + '\n';
});
}
this.properties['Vertex Grid'].forEach(row => {
row.forEach(point => {
point.forEach(val => content += val + '\n');
});
});
if (this.properties['Number of Tiles'] > 1) {
this.properties['Tile Transformation Matrices'].forEach(matrix => {
matrix.forEach(row => {
row.forEach(val => content += val + '\n');
});
});
}
this.properties['Normal Correctors'].forEach(val => content += val + '\n');
const blob = new Blob([content], {type: 'text/plain'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
}
}
// Example usage
// const sur = new SURFile('example.sur');
// await sur.read();
// sur.printProperties();
// await sur.write('output.sur');
7. C class for .SUR file
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char* file_identifier;
int version_number;
int u_resolution;
int v_resolution;
int number_of_tiles;
double camera_position[3];
double view_direction[3];
double image_plane_center[3];
double image_plane_horizontal_vector[3];
double image_plane_vertical_vector[3];
double focal_length;
double scale;
double eye_separation;
double clipping_plane_distance;
double*** vertex_grid;
double**** tile_transformation_matrices;
int* normal_correctors;
} SURProperties;
typedef struct {
char* filename;
SURProperties properties;
} SURFile;
SURFile* sur_create(const char* filename) {
SURFile* sur = (SURFile*)malloc(sizeof(SURFile));
sur->filename = strdup(filename);
memset(&sur->properties, 0, sizeof(SURProperties));
return sur;
}
void sur_read(SURFile* sur) {
FILE* f = fopen(sur->filename, "r");
if (!f) return;
char line[256];
int index = 0;
fgets(line, sizeof(line), f);
sur->properties.file_identifier = strdup(line);
fgets(line, sizeof(line), f);
sur->properties.version_number = atoi(line);
fgets(line, sizeof(line), f);
sur->properties.u_resolution = atoi(line);
fgets(line, sizeof(line), f);
sur->properties.v_resolution = atoi(line);
fgets(line, sizeof(line), f);
sur->properties.number_of_tiles = atoi(line);
if (sur->properties.version_number >= 2) {
for (int i = 0; i < 3; i++) {
fgets(line, sizeof(line), f);
sur->properties.camera_position[i] = atof(line);
}
for (int i = 0; i < 3; i++) {
fgets(line, sizeof(line), f);
sur->properties.view_direction[i] = atof(line);
}
for (int i = 0; i < 3; i++) {
fgets(line, sizeof(line), f);
sur->properties.image_plane_center[i] = atof(line);
}
for (int i = 0; i < 3; i++) {
fgets(line, sizeof(line), f);
sur->properties.image_plane_horizontal_vector[i] = atof(line);
}
for (int i = 0; i < 3; i++) {
fgets(line, sizeof(line), f);
sur->properties.image_plane_vertical_vector[i] = atof(line);
}
fgets(line, sizeof(line), f);
sur->properties.focal_length = atof(line);
fgets(line, sizeof(line), f);
sur->properties.scale = atof(line);
fgets(line, sizeof(line), f);
sur->properties.eye_separation = atof(line);
fgets(line, sizeof(line), f);
sur->properties.clipping_plane_distance = atof(line);
}
sur->properties.vertex_grid = (double***)malloc(sur->properties.u_resolution * sizeof(double**));
for (int i = 0; i < sur->properties.u_resolution; i++) {
sur->properties.vertex_grid[i] = (double**)malloc(sur->properties.v_resolution * sizeof(double*));
for (int j = 0; j < sur->properties.v_resolution; j++) {
sur->properties.vertex_grid[i][j] = (double*)malloc(3 * sizeof(double));
for (int k = 0; k < 3; k++) {
fgets(line, sizeof(line), f);
sur->properties.vertex_grid[i][j][k] = atof(line);
}
}
}
if (sur->properties.number_of_tiles > 1) {
sur->properties.tile_transformation_matrices = (double****)malloc(sur->properties.number_of_tiles * sizeof(double***));
for (int k = 0; k < sur->properties.number_of_tiles; k++) {
sur->properties.tile_transformation_matrices[k] = (double***)malloc(4 * sizeof(double**));
for (int row = 0; row < 4; row++) {
sur->properties.tile_transformation_matrices[k][row] = (double**)malloc(3 * sizeof(double*));
for (int col = 0; col < 3; col++) {
sur->properties.tile_transformation_matrices[k][row][col] = (double*)malloc(sizeof(double));
fgets(line, sizeof(line), f);
*sur->properties.tile_transformation_matrices[k][row][col] = atof(line);
}
}
}
}
sur->properties.normal_correctors = (int*)malloc(sur->properties.number_of_tiles * sizeof(int));
for (int k = 0; k < sur->properties.number_of_tiles; k++) {
fgets(line, sizeof(line), f);
sur->properties.normal_correctors[k] = atoi(line);
}
fclose(f);
}
void sur_print_properties(SURFile* sur) {
printf("File Identifier: %s\n", sur->properties.file_identifier);
printf("Version Number: %d\n", sur->properties.version_number);
printf("U Resolution: %d\n", sur->properties.u_resolution);
printf("V Resolution: %d\n", sur->properties.v_resolution);
printf("Number of Tiles: %d\n", sur->properties.number_of_tiles);
// Similarly print other properties, vectors, grids, etc. (omitted for brevity, use loops for arrays)
}
void sur_write(SURFile* sur, const char* filename) {
FILE* f = fopen(filename, "w");
if (!f) return;
fprintf(f, "SurfaceDataFile\n");
fprintf(f, "%d\n", sur->properties.version_number);
fprintf(f, "%d\n", sur->properties.u_resolution);
fprintf(f, "%d\n", sur->properties.v_resolution);
fprintf(f, "%d\n", sur->properties.number_of_tiles);
if (sur->properties.version_number >= 2) {
for (int i = 0; i < 3; i++) fprintf(f, "%f\n", sur->properties.camera_position[i]);
for (int i = 0; i < 3; i++) fprintf(f, "%f\n", sur->properties.view_direction[i]);
for (int i = 0; i < 3; i++) fprintf(f, "%f\n", sur->properties.image_plane_center[i]);
for (int i = 0; i < 3; i++) fprintf(f, "%f\n", sur->properties.image_plane_horizontal_vector[i]);
for (int i = 0; i < 3; i++) fprintf(f, "%f\n", sur->properties.image_plane_vertical_vector[i]);
fprintf(f, "%f\n", sur->properties.focal_length);
fprintf(f, "%f\n", sur->properties.scale);
fprintf(f, "%f\n", sur->properties.eye_separation);
fprintf(f, "%f\n", sur->properties.clipping_plane_distance);
}
for (int i = 0; i < sur->properties.u_resolution; i++) {
for (int j = 0; j < sur->properties.v_resolution; j++) {
for (int k = 0; k < 3; k++) {
fprintf(f, "%f\n", sur->properties.vertex_grid[i][j][k]);
}
}
}
if (sur->properties.number_of_tiles > 1) {
for (int k = 0; k < sur->properties.number_of_tiles; k++) {
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 3; col++) {
fprintf(f, "%f\n", *sur->properties.tile_transformation_matrices[k][row][col]);
}
}
}
}
for (int k = 0; k < sur->properties.number_of_tiles; k++) {
fprintf(f, "%d\n", sur->properties.normal_correctors[k]);
}
fclose(f);
}
void sur_free(SURFile* sur) {
free(sur->file_identifier);
// Free allocated arrays (vertex_grid, matrices, normal_correctors) - omitted for brevity, use nested free loops
free(sur->filename);
free(sur);
}
// Example usage
// int main() {
// SURFile* sur = sur_create("example.sur");
// sur_read(sur);
// sur_print_properties(sur);
// sur_write(sur, "output.sur");
// sur_free(sur);
// return 0;
// }