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.

  1. 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)
  1. Two direct download links for files of format .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.

  1. Ghost blog embedded HTML JavaScript for drag and drop .SAT file to dump properties:
Drag and drop .SAT file here

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.

  1. 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')
  1. 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");
    // }
}
  1. 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');
  1. 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;
// }