Task 635: .SAT File Format
Task 635: .SAT File Format
.SAT File Format Specifications
The .SAT file format is the Standard ACIS Text (SAT) format used by the ACIS geometric modeling kernel for storing 3D model data in ASCII text form. It is used in CAD software for precise representation of solids, surfaces, and curves. The format is open, backward-compatible across versions, and includes a header, entity records, optional history section, and an end marker. The binary counterpart is .SAB, but the task focuses on .SAT.
- List of all the properties of this file format intrinsic to its file system:
- Encoded version number (integer: 100 * major + minor, e.g., 712 for version 7.1.2)
- Total number of saved data records (integer, or 0 if unknown)
- Count of entities in the original entity list (integer)
- History flag (integer: least significant bit indicates if history is saved)
- Product ID (string: the product that produced the file)
- ACIS version (string: e.g., "ACIS 7.0 NT")
- Date the file was produced (string: in C ctime format, e.g., "Mon Apr 09 16:44:18 2001")
- Millimeters per unit in the model (double)
- Resabs value (real: absolute resolution when produced)
- Resnor value (real: normal resolution when produced)
- Two direct download links for files of format .SAT:
- https://isr.umd.edu/Labs/CIM/vm/xlator/acis.sat (sample for a cube with cylindrical hole; note: the content is displayed on the page, save as .sat)
- https://paulbourke.net/dataformats/sat/sample.sat (example from format documentation; note: extract example content from sat.pdf and save as .sat)
Note: Direct .SAT files are often embedded in documentation or require registration on CAD sites like GrabCAD or CGTrader. The above are sources with sample content that can be saved as .sat files.
- Ghost blog embedded HTML JavaScript for drag and drop .SAT file to dump properties:
This HTML/JS can be embedded in a Ghost blog post. It allows dragging and dropping a .SAT file, parses the header, and dumps the properties to the screen.
- Python class for opening, decoding, reading, writing, and printing .SAT properties:
class SatFileHandler:
def __init__(self, filepath):
self.filepath = filepath
self.properties = {}
self.content = None
def read_decode(self):
with open(self.filepath, 'r') as f:
self.content = f.read()
tokens = self.content.replace('\n', ' ').split()
index = 0
self.properties['Encoded Version Number'] = int(tokens[index])
index += 1
self.properties['Total Number of Records'] = int(tokens[index])
index += 1
self.properties['Number of Entities'] = int(tokens[index])
index += 1
self.properties['History Flag'] = int(tokens[index])
index += 1
# Product ID
len_ = int(tokens[index])
index += 1
str_ = ''
while len(str_) < len_:
str_ += ( ' ' if str_ else '') + tokens[index]
index += 1
self.properties['Product ID'] = str_
# ACIS Version
len_ = int(tokens[index])
index += 1
str_ = ''
while len(str_) < len_:
str_ += ( ' ' if str_ else '') + tokens[index]
index += 1
self.properties['ACIS Version'] = str_
# Date
len_ = int(tokens[index])
index += 1
str_ = ''
while len(str_) < len_:
str_ += ( ' ' if str_ else '') + tokens[index]
index += 1
self.properties['Date'] = str_
self.properties['Units'] = float(tokens[index])
index += 1
self.properties['Resabs'] = float(tokens[index])
index += 1
self.properties['Resnor'] = float(tokens[index])
index += 1
def print_properties(self):
for key, value in self.properties.items():
print(f"{key}: {value}")
def write(self, output_path):
if self.content:
with open(output_path, 'w') as f:
f.write(self.content)
else:
print("No content to write. Read the file first.")
# Example usage:
# handler = SatFileHandler('sample.sat')
# handler.read_decode()
# handler.print_properties()
# handler.write('output.sat')
- Java class for opening, decoding, reading, writing, and printing .SAT properties:
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class SatFileHandler {
private String filepath;
private Map<String, Object> properties = new HashMap<>();
private String content;
public SatFileHandler(String filepath) {
this.filepath = filepath;
}
public void readDecode() throws FileNotFoundException {
StringBuilder sb = new StringBuilder();
Scanner scanner = new Scanner(new File(filepath));
while (scanner.hasNextLine()) {
sb.append(scanner.nextLine()).append(" ");
}
content = sb.toString();
scanner.close();
String[] tokens = content.split("\\s+");
int index = 0;
properties.put("Encoded Version Number", Integer.parseInt(tokens[index++]));
properties.put("Total Number of Records", Integer.parseInt(tokens[index++]));
properties.put("Number of Entities", Integer.parseInt(tokens[index++]));
properties.put("History Flag", Integer.parseInt(tokens[index++]));
// Product ID
int len = Integer.parseInt(tokens[index++]);
StringBuilder str = new StringBuilder();
while (str.length() < len) {
if (str.length() > 0) str.append(" ");
str.append(tokens[index++]);
}
properties.put("Product ID", str.toString());
// ACIS Version
len = Integer.parseInt(tokens[index++]);
str = new StringBuilder();
while (str.length() < len) {
if (str.length() > 0) str.append(" ");
str.append(tokens[index++]);
}
properties.put("ACIS Version", str.toString());
// Date
len = Integer.parseInt(tokens[index++]);
str = new StringBuilder();
while (str.length() < len) {
if (str.length() > 0) str.append(" ");
str.append(tokens[index++]);
}
properties.put("Date", str.toString());
properties.put("Units", Double.parseDouble(tokens[index++]));
properties.put("Resabs", Double.parseDouble(tokens[index++]));
properties.put("Resnor", Double.parseDouble(tokens[index++]));
}
public void printProperties() {
for (Map.Entry<String, Object> entry : properties.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
public void write(String outputPath) throws IOException {
if (content != null) {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputPath))) {
writer.write(content);
}
} else {
System.out.println("No content to write. Read the file first.");
}
}
// Example usage:
// public static void main(String[] args) throws IOException {
// SatFileHandler handler = new SatFileHandler("sample.sat");
// handler.readDecode();
// handler.printProperties();
// handler.write("output.sat");
// }
}
- JavaScript class for opening, decoding, reading, writing, and printing .SAT properties:
class SatFileHandler {
constructor(filepath) {
this.filepath = filepath;
this.properties = {};
this.content = null;
}
async readDecode() {
// Note: In Node.js, use fs module
const fs = require('fs');
this.content = fs.readFileSync(this.filepath, 'utf8');
const tokens = this.content.replace(/\n/g, ' ').split(/\s+/).filter(t => t);
let index = 0;
this.properties['Encoded Version Number'] = parseInt(tokens[index++]);
this.properties['Total Number of Records'] = parseInt(tokens[index++]);
this.properties['Number of Entities'] = parseInt(tokens[index++]);
this.properties['History Flag'] = parseInt(tokens[index++]);
// Product ID
let len = parseInt(tokens[index++]);
let str = '';
while (str.length < len) {
str += (str ? ' ' : '') + tokens[index++];
}
this.properties['Product ID'] = str;
// ACIS Version
len = parseInt(tokens[index++]);
str = '';
while (str.length < len) {
str += (str ? ' ' : '') + tokens[index++];
}
this.properties['ACIS Version'] = str;
// Date
len = parseInt(tokens[index++]);
str = '';
while (str.length < len) {
str += (str ? ' ' : '') + tokens[index++];
}
this.properties['Date'] = str;
this.properties['Units'] = parseFloat(tokens[index++]);
this.properties['Resabs'] = parseFloat(tokens[index++]);
this.properties['Resnor'] = parseFloat(tokens[index++]);
}
printProperties() {
for (const key in this.properties) {
console.log(`${key}: ${this.properties[key]}`);
}
}
write(outputPath) {
if (this.content) {
const fs = require('fs');
fs.writeFileSync(outputPath, this.content);
} else {
console.log('No content to write. Read the file first.');
}
}
}
// Example usage:
// const handler = new SatFileHandler('sample.sat');
// await handler.readDecode();
// handler.printProperties();
// handler.write('output.sat');
- C class for opening, decoding, reading, writing, and printing .SAT properties:
Note: Using C++ for class support, as "c class" likely implies C++.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>
#include <vector>
class SatFileHandler {
private:
std::string filepath;
std::map<std::string, std::string> properties;
std::string content;
public:
SatFileHandler(const std::string& fp) : filepath(fp) {}
void readDecode() {
std::ifstream file(filepath);
std::stringstream buffer;
buffer << file.rdbuf();
content = buffer.str();
file.close();
std::stringstream ss(content);
std::vector<std::string> tokens;
std::string token;
while (ss >> token) {
tokens.push_back(token);
}
size_t index = 0;
properties["Encoded Version Number"] = tokens[index++];
properties["Total Number of Records"] = tokens[index++];
properties["Number of Entities"] = tokens[index++];
properties["History Flag"] = tokens[index++];
// Product ID
int len = std::stoi(tokens[index++]);
std::string str = "";
while (static_cast<int>(str.length()) < len) {
if (!str.empty()) str += " ";
str += tokens[index++];
}
properties["Product ID"] = str;
// ACIS Version
len = std::stoi(tokens[index++]);
str = "";
while (static_cast<int>(str.length()) < len) {
if (!str.empty()) str += " ";
str += tokens[index++];
}
properties["ACIS Version"] = str;
// Date
len = std::stoi(tokens[index++]);
str = "";
while (static_cast<int>(str.length()) < len) {
if (!str.empty()) str += " ";
str += tokens[index++];
}
properties["Date"] = str;
properties["Units"] = tokens[index++];
properties["Resabs"] = tokens[index++];
properties["Resnor"] = tokens[index++];
}
void printProperties() {
for (const auto& pair : properties) {
std::cout << pair.first << ": " << pair.second << std::endl;
}
}
void write(const std::string& outputPath) {
if (!content.empty()) {
std::ofstream outFile(outputPath);
outFile << content;
outFile.close();
} else {
std::cout << "No content to write. Read the file first." << std::endl;
}
}
};
// Example usage:
// int main() {
// SatFileHandler handler("sample.sat");
// handler.readDecode();
// handler.printProperties();
// handler.write("output.sat");
// return 0;
// }