Task 308: .IGES File Format

Task 308: .IGES File Format

IGES File Format Specifications

The .IGES file format (Initial Graphics Exchange Specification) is a vendor-neutral ASCII-based standard for exchanging CAD data, including 2D and 3D geometry, annotations, and other model information. It was originally developed by the U.S. Air Force in 1979 and standardized by ANSI as Y14.26M. The most commonly used version is 5.3 (published in 1996), which supports boundary representation (B-Rep), constructive solid geometry (CSG), and wireframe models. The file structure consists of five sections: Start (S), Global (G), Directory Entry (D), Parameter Data (P), and Terminate (T). Each line is fixed at 80 characters, with the section identifier in column 73 and a sequence number in columns 74-80. The format is text-based, making it human-readable but verbose. Specifications can be found in the official document "Initial Graphics Exchange Specification (IGES) Version 5.3" from the National Institute of Standards and Technology (NIST), available as a PDF.

  1. List of Properties Intrinsic to the File Format
    The properties intrinsic to the .IGES file system are primarily the metadata parameters in the Global (G) section, which define file-wide settings, delimiters, units, precision, and authorship. These are parsed from a concatenated string of Global lines (columns 1-72) using delimiters (default: comma for parameters, semicolon for records). There are 25 mandatory parameters in IGES 5.3, with an optional 26th. They are listed below with their order, logical type, description, and defaults/constraints:
  2. Parameter Delimiter Character (String/Char): Character separating parameters (default: ',').
  3. Record Delimiter Character (String/Char): Character terminating records (default: ';').
  4. Product Identification from Sending System (String): Name or ID of the product/model from the sender.
  5. File Name (String): Name of the IGES file.
  6. Native System ID (String): Identifier of the system/software that generated the file.
  7. Preprocessor Version (String): Version of the IGES preprocessor used.
  8. Number of Bits for Integers (Integer): Bits used for integer representation (e.g., 32).
  9. Single Precision Magnitude (Integer): Maximum power of 10 for single-precision floats.
  10. Single Precision Significance (Integer): Number of significant digits for single-precision floats.
  11. Double Precision Magnitude (Integer): Maximum power of 10 for double-precision floats.
  12. Double Precision Significance (Integer): Number of significant digits for double-precision floats.
  13. Product Identification for Receiving System (String): Name or ID of the product for the receiver (defaults to parameter 3 if blank).
  14. Model Space Scale (Float): Scale factor for model units to real-world (default: 1.0).
  15. Units Flag (Integer): Code for units (1=inches, 2=mm, etc.; default: 1).
  16. Units Name (String): Custom units name (required if units flag=3; e.g., "INCH").
  17. Max Line Weight Gradations (Integer): Maximum number of line thickness levels.
  18. Width of Max Line Weight (Float): Width of the thickest line in model units.
  19. Date and Time of File Generation (String): Timestamp when the file was created (e.g., "13H20250927.120000").
  20. Minimum Resolution (Float): Smallest distinguishable distance in model space.
  21. Approximate Maximum Coordinate (Float): Largest expected coordinate value in the model.
  22. Name of Author (String): Author's name.
  23. Author's Organization (String): Author's company or organization.
  24. IGES Version Flag (Integer): IGES version code (e.g., 11 for 5.3).
  25. Drafting Standard Flag (Integer): Code for drafting standard (0=none, 1=GKS, etc.).
  26. Date and Time Model Last Modified (String): Timestamp of last model change.
  27. Application Protocol Identifier (String, optional): Identifier for application-specific subset or protocol.

These properties are "intrinsic" as they define the file's encoding, units, precision, and metadata, affecting how the entire file is interpreted.

  1. Two Direct Download Links for .IGES Files
  1. Ghost Blog Embedded HTML JavaScript for Drag-and-Drop .IGES File Dump
    Below is embeddable HTML with JavaScript for a Ghost blog post. It creates a drop zone; when a .IGES file is dropped, it reads the file, parses the Global section, extracts the properties, and displays them on the screen.
Drag and drop .IGES file here
  1. Python Class for .IGES File Handling
import os

class IGESParser:
    def __init__(self):
        self.properties = []
        self.global_str = ''
        self.other_content = ''  # For writing back

    def open_file(self, filepath):
        with open(filepath, 'r') as f:
            content = f.read()
        lines = content.splitlines()
        self.global_str = ''
        self.other_content = ''
        in_global = False
        for line in lines:
            if len(line) < 73:
                continue
            if line[72] == 'G':
                in_global = True
                self.global_str += line[:72]
            else:
                if in_global:
                    in_global = False
                self.other_content += line + '\n'

    def decode_properties(self):
        index = 0
        param_delim = ','
        record_delim = ';'
        def skip_spaces():
            nonlocal index
            while index < len(self.global_str) and self.global_str[index] == ' ':
                index += 1

        def read_token(delim):
            skip_spaces()
            token = ''
            while index < len(self.global_str) and self.global_str[index] not in (delim, record_delim):
                token += self.global_str[index]
                index += 1
            if index < len(self.global_str) and self.global_str[index] == delim:
                index += 1
            return token.strip()

        def parse_hollerith(token):
            if 'H' in token:
                parts = token.split('H')
                if len(parts) == 2 and parts[0].isdigit():
                    length = int(parts[0])
                    return parts[1][:length]
            return token

        # Parse first two with defaults
        token = read_token(param_delim)
        param_delim = parse_hollerith(token)[0] if token else ','
        token = read_token(record_delim)
        record_delim = parse_hollerith(token)[0] if token else ';'

        # Parse rest
        self.properties = []
        while index < len(self.global_str):
            skip_spaces()
            if index >= len(self.global_str) or self.global_str[index] == record_delim:
                break
            token = ''
            in_hollerith = False
            h_count = ''
            h_length = 0
            while index < len(self.global_str) and self.global_str[index] not in (param_delim, record_delim):
                ch = self.global_str[index]
                index += 1
                if not in_hollerith and ch.isdigit():
                    h_count += ch
                elif not in_hollerith and ch == 'H':
                    in_hollerith = True
                    h_length = int(h_count) if h_count else 0
                    h_count = ''
                else:
                    token += ch
            if in_hollerith:
                token = token[:h_length]
            self.properties.append(token.strip())
            if index < len(self.global_str) and self.global_str[index] == param_delim:
                index += 1

    def print_properties(self):
        labels = [
            'Parameter Delimiter', 'Record Delimiter', 'Sending Product ID', 'File Name', 'Native System ID',
            'Preprocessor Version', 'Integer Bits', 'Single Prec Magnitude', 'Single Prec Significance',
            'Double Prec Magnitude', 'Double Prec Significance', 'Receiving Product ID', 'Model Scale',
            'Units Flag', 'Units Name', 'Line Weight Gradations', 'Max Line Width', 'Generation Date',
            'Minimum Resolution', 'Max Coordinate', 'Author Name', 'Organization', 'IGES Version Flag',
            'Drafting Standard Flag', 'Modified Date', 'Application Protocol'
        ]
        for i, prop in enumerate(self.properties):
            print(f"{labels[i] if i < len(labels) else 'Extra'}: {prop}")

    def write_file(self, output_path, new_properties=None):
        if new_properties:
            self.properties = new_properties
        # Reconstruct global_str (simplified: assumes default delims and Hollerith for strings)
        global_rebuilt = '1H' + self.properties[0] + ',1H' + self.properties[1] + ','
        for prop in self.properties[2:]:
            if prop.isdigit() or '.' in prop or 'E' in prop.upper():
                global_rebuilt += prop + ','
            else:
                global_rebuilt += str(len(prop)) + 'H' + prop + ','
        global_rebuilt = global_rebuilt.rstrip(',') + ';'
        # Pad and split into 72-char chunks with G sections
        global_lines = ''
        seq = 1
        for i in range(0, len(global_rebuilt), 72):
            chunk = global_rebuilt[i:i+72].ljust(72)
            global_lines += chunk + f'G{seq:>7}\n'
            seq += 1
        with open(output_path, 'w') as f:
            f.write(global_lines + self.other_content)  # Append other sections

# Example usage:
# parser = IGESParser()
# parser.open_file('example.iges')
# parser.decode_properties()
# parser.print_properties()
# parser.write_file('modified.iges')
  1. Java Class for .IGES File Handling
import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class IGESParser {
    private List<String> properties = new ArrayList<>();
    private String globalStr = "";
    private String otherContent = "";

    public void openFile(String filepath) throws IOException {
        StringBuilder content = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new FileReader(filepath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line).append("\n");
            }
        }
        String[] lines = content.toString().split("\n");
        globalStr = "";
        otherContent = "";
        boolean inGlobal = false;
        for (String line : lines) {
            if (line.length() < 73) continue;
            if (line.charAt(72) == 'G') {
                inGlobal = true;
                globalStr += line.substring(0, 72);
            } else {
                if (inGlobal) inGlobal = false;
                otherContent += line + "\n";
            }
        }
    }

    public void decodeProperties() {
        int index = 0;
        char paramDelim = ',';
        char recordDelim = ';';
        final int[] idx = {index};  // Mutable index

        Runnable skipSpaces = () -> {
            while (idx[0] < globalStr.length() && globalStr.charAt(idx[0]) == ' ') idx[0]++;
        };

        String readToken = (char delim) -> {
            skipSpaces.run();
            StringBuilder token = new StringBuilder();
            while (idx[0] < globalStr.length() && globalStr.charAt(idx[0]) != delim && globalStr.charAt(idx[0]) != recordDelim) {
                token.append(globalStr.charAt(idx[0]++));
            }
            if (idx[0] < globalStr.length() && globalStr.charAt(idx[0]) == delim) idx[0]++;
            return token.toString().trim();
        };

        String parseHollerith = (String token) -> {
            if (token.contains("H")) {
                String[] parts = token.split("H");
                if (parts.length == 2 && parts[0].matches("\\d+")) {
                    int length = Integer.parseInt(parts[0]);
                    return parts[1].substring(0, Math.min(length, parts[1].length()));
                }
            }
            return token;
        };

        // Parse first two with defaults
        String token = readToken.apply(paramDelim);
        paramDelim = !token.isEmpty() ? parseHollerith.apply(token).charAt(0) : ',';
        token = readToken.apply(recordDelim);
        recordDelim = !token.isEmpty() ? parseHollerith.apply(token).charAt(0) : ';';

        // Parse rest
        properties.clear();
        while (idx[0] < globalStr.length()) {
            skipSpaces.run();
            if (globalStr.charAt(idx[0]) == recordDelim) break;
            StringBuilder tokenBuilder = new StringBuilder();
            boolean inHollerith = false;
            String hCount = "";
            int hLength = 0;
            while (idx[0] < globalStr.length() && globalStr.charAt(idx[0]) != paramDelim && globalStr.charAt(idx[0]) != recordDelim) {
                char ch = globalStr.charAt(idx[0]++);
                if (!inHollerith && Character.isDigit(ch)) {
                    hCount += ch;
                } else if (!inHollerith && ch == 'H') {
                    inHollerith = true;
                    hLength = !hCount.isEmpty() ? Integer.parseInt(hCount) : 0;
                    hCount = "";
                } else {
                    tokenBuilder.append(ch);
                }
            }
            if (inHollerith) {
                token = tokenBuilder.toString().substring(0, hLength);
            } else {
                token = tokenBuilder.toString();
            }
            properties.add(token.trim());
            if (idx[0] < globalStr.length() && globalStr.charAt(idx[0]) == paramDelim) idx[0]++;
        }
        index = idx[0];
    }

    public void printProperties() {
        String[] labels = {
            "Parameter Delimiter", "Record Delimiter", "Sending Product ID", "File Name", "Native System ID",
            "Preprocessor Version", "Integer Bits", "Single Prec Magnitude", "Single Prec Significance",
            "Double Prec Magnitude", "Double Prec Significance", "Receiving Product ID", "Model Scale",
            "Units Flag", "Units Name", "Line Weight Gradations", "Max Line Width", "Generation Date",
            "Minimum Resolution", "Max Coordinate", "Author Name", "Organization", "IGES Version Flag",
            "Drafting Standard Flag", "Modified Date", "Application Protocol"
        };
        for (int i = 0; i < properties.size(); i++) {
            System.out.println((i < labels.length ? labels[i] : "Extra") + ": " + properties.get(i));
        }
    }

    public void writeFile(String outputPath, List<String> newProperties) throws IOException {
        if (newProperties != null) properties = newProperties;
        // Reconstruct globalStr (simplified)
        StringBuilder globalRebuilt = new StringBuilder("1H" + properties.get(0) + ",1H" + properties.get(1) + ",");
        for (int i = 2; i < properties.size(); i++) {
            String prop = properties.get(i);
            if (prop.matches("[-+]?\\d*\\.?\\d+([eE][-+]?\\d+)?") || prop.matches("\\d+")) {
                globalRebuilt.append(prop).append(",");
            } else {
                globalRebuilt.append(prop.length()).append("H").append(prop).append(",");
            }
        }
        globalRebuilt = new StringBuilder(globalRebuilt.toString().replaceAll(",$", ";"));
        // Pad and split into lines
        StringBuilder globalLines = new StringBuilder();
        int seq = 1;
        for (int i = 0; i < globalRebuilt.length(); i += 72) {
            String chunk = globalRebuilt.substring(i, Math.min(i + 72, globalRebuilt.length()));
            chunk += " ".repeat(72 - chunk.length());
            globalLines.append(chunk).append(String.format("G%7d\n", seq++));
        }
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(outputPath))) {
            writer.write(globalLines.toString() + otherContent);
        }
    }

    // Example usage:
    // public static void main(String[] args) throws IOException {
    //     IGESParser parser = new IGESParser();
    //     parser.openFile("example.iges");
    //     parser.decodeProperties();
    //     parser.printProperties();
    //     parser.writeFile("modified.iges", null);
    // }
}
  1. JavaScript Class for .IGES File Handling
class IGESParser {
  constructor() {
    this.properties = [];
    this.globalStr = '';
    this.otherContent = '';
  }

  openFile(fileContent) {
    const lines = fileContent.split('\n');
    this.globalStr = '';
    this.otherContent = '';
    let inGlobal = false;
    lines.forEach(line => {
      if (line.length < 73) return;
      if (line[72] === 'G') {
        inGlobal = true;
        this.globalStr += line.substring(0, 72);
      } else {
        if (inGlobal) inGlobal = false;
        this.otherContent += line + '\n';
      }
    });
  }

  decodeProperties() {
    let index = 0;
    let paramDelim = ',';
    let recordDelim = ';';
    const skipSpaces = () => {
      while (index < this.globalStr.length && this.globalStr[index] === ' ') index++;
    };
    const readToken = (delim) => {
      skipSpaces();
      let token = '';
      while (index < this.globalStr.length && this.globalStr[index] !== delim && this.globalStr[index] !== recordDelim) {
        token += this.globalStr[index++];
      }
      if (index < this.globalStr.length && this.globalStr[index] === delim) index++;
      return token.trim();
    };
    const parseHollerith = (token) => {
      const match = token.match(/^(\d+)H(.*)$/);
      if (match) return match[2].substring(0, parseInt(match[1]));
      return token;
    };

    // Parse first two with defaults
    let token = readToken(paramDelim);
    paramDelim = parseHollerith(token)[0] || ',';
    token = readToken(recordDelim);
    recordDelim = parseHollerith(token)[0] || ';';

    // Parse rest
    this.properties = [];
    while (index < this.globalStr.length) {
      skipSpaces();
      if (this.globalStr[index] === recordDelim) break;
      token = '';
      let inHollerith = false;
      let hLength = 0;
      let hCount = '';
      while (index < this.globalStr.length && this.globalStr[index] !== paramDelim && this.globalStr[index] !== recordDelim) {
        let ch = this.globalStr[index++];
        if (!inHollerith && /\d/.test(ch)) hCount += ch;
        else if (!inHollerith && ch === 'H') {
          inHollerith = true;
          hLength = parseInt(hCount) || 0;
          hCount = '';
        } else token += ch;
      }
      if (inHollerith) token = token.substring(0, hLength);
      this.properties.push(token.trim());
      if (index < this.globalStr.length && this.globalStr[index] === paramDelim) index++;
    }
  }

  printProperties() {
    const labels = [
      'Parameter Delimiter', 'Record Delimiter', 'Sending Product ID', 'File Name', 'Native System ID',
      'Preprocessor Version', 'Integer Bits', 'Single Prec Magnitude', 'Single Prec Significance',
      'Double Prec Magnitude', 'Double Prec Significance', 'Receiving Product ID', 'Model Scale',
      'Units Flag', 'Units Name', 'Line Weight Gradations', 'Max Line Width', 'Generation Date',
      'Minimum Resolution', 'Max Coordinate', 'Author Name', 'Organization', 'IGES Version Flag',
      'Drafting Standard Flag', 'Modified Date', 'Application Protocol'
    ];
    this.properties.forEach((prop, i) => {
      console.log(`${labels[i] || 'Extra'}: ${prop}`);
    });
  }

  writeFile(newProperties = null) {
    if (newProperties) this.properties = newProperties;
    // Reconstruct globalStr (simplified)
    let globalRebuilt = `1H${this.properties[0]},1H${this.properties[1]},`;
    for (let i = 2; i < this.properties.length; i++) {
      const prop = this.properties[i];
      if (/^[-+]?\d*\.?\d+([eE][-+]?\d+)?$/.test(prop) || /^\d+$/.test(prop)) {
        globalRebuilt += `${prop},`;
      } else {
        globalRebuilt += `${prop.length}H${prop},`;
      }
    }
    globalRebuilt = globalRebuilt.replace(/,$/, ';');
    // Pad and split
    let globalLines = '';
    let seq = 1;
    for (let i = 0; i < globalRebuilt.length; i += 72) {
      let chunk = globalRebuilt.substring(i, i + 72).padEnd(72, ' ');
      globalLines += `${chunk}G${seq.toString().padStart(7, ' ')}\n`;
      seq++;
    }
    return globalLines + this.otherContent;  // Return string for Node.js fs or browser download
  }
}

// Example usage in Node.js:
// const fs = require('fs');
// const parser = new IGESParser();
// const content = fs.readFileSync('example.iges', 'utf8');
// parser.openFile(content);
// parser.decodeProperties();
// parser.printProperties();
// const output = parser.writeFile();
// fs.writeFileSync('modified.iges', output);
  1. C++ Class for .IGES File Handling
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <regex>
#include <iomanip>

class IGESParser {
private:
    std::vector<std::string> properties;
    std::string global_str;
    std::string other_content;

public:
    void open_file(const std::string& filepath) {
        std::ifstream file(filepath);
        std::string line;
        global_str = "";
        other_content = "";
        bool in_global = false;
        while (std::getline(file, line)) {
            if (line.length() < 73) continue;
            if (line[72] == 'G') {
                in_global = true;
                global_str += line.substr(0, 72);
            } else {
                if (in_global) in_global = false;
                other_content += line + "\n";
            }
        }
        file.close();
    }

    void decode_properties() {
        size_t index = 0;
        char param_delim = ',';
        char record_delim = ';';
        auto skip_spaces = [&]() {
            while (index < global_str.length() && global_str[index] == ' ') ++index;
        };
        auto read_token = [&](char delim) -> std::string {
            skip_spaces();
            std::string token;
            while (index < global_str.length() && global_str[index] != delim && global_str[index] != record_delim) {
                token += global_str[index++];
            }
            if (index < global_str.length() && global_str[index] == delim) ++index;
            return token;
        };
        auto parse_hollerith = [](const std::string& token) -> std::string {
            size_t h_pos = token.find('H');
            if (h_pos != std::string::npos) {
                std::string num_str = token.substr(0, h_pos);
                if (std::regex_match(num_str, std::regex("\\d+"))) {
                    int length = std::stoi(num_str);
                    return token.substr(h_pos + 1, length);
                }
            }
            return token;
        };

        // Parse first two with defaults
        std::string token = read_token(param_delim);
        param_delim = !token.empty() ? parse_hollerith(token)[0] : ',';
        token = read_token(record_delim);
        record_delim = !token.empty() ? parse_hollerith(token)[0] : ';';

        // Parse rest
        properties.clear();
        while (index < global_str.length()) {
            skip_spaces();
            if (global_str[index] == record_delim) break;
            std::string token_str;
            bool in_hollerith = false;
            std::string h_count;
            int h_length = 0;
            while (index < global_str.length() && global_str[index] != param_delim && global_str[index] != record_delim) {
                char ch = global_str[index++];
                if (!in_hollerith && isdigit(ch)) {
                    h_count += ch;
                } else if (!in_hollerith && ch == 'H') {
                    in_hollerith = true;
                    h_length = !h_count.empty() ? std::stoi(h_count) : 0;
                    h_count = "";
                } else {
                    token_str += ch;
                }
            }
            if (in_hollerith) token_str = token_str.substr(0, h_length);
            properties.push_back(token_str);
            if (index < global_str.length() && global_str[index] == param_delim) ++index;
        }
    }

    void print_properties() {
        std::vector<std::string> labels = {
            "Parameter Delimiter", "Record Delimiter", "Sending Product ID", "File Name", "Native System ID",
            "Preprocessor Version", "Integer Bits", "Single Prec Magnitude", "Single Prec Significance",
            "Double Prec Magnitude", "Double Prec Significance", "Receiving Product ID", "Model Scale",
            "Units Flag", "Units Name", "Line Weight Gradations", "Max Line Width", "Generation Date",
            "Minimum Resolution", "Max Coordinate", "Author Name", "Organization", "IGES Version Flag",
            "Drafting Standard Flag", "Modified Date", "Application Protocol"
        };
        for (size_t i = 0; i < properties.size(); ++i) {
            std::cout << (i < labels.size() ? labels[i] : "Extra") << ": " << properties[i] << std::endl;
        }
    }

    void write_file(const std::string& output_path, const std::vector<std::string>& new_properties = {}) {
        if (!new_properties.empty()) properties = new_properties;
        // Reconstruct global_str (simplified)
        std::string global_rebuilt = "1H" + properties[0] + ",1H" + properties[1] + ",";
        for (size_t i = 2; i < properties.size(); ++i) {
            const std::string& prop = properties[i];
            if (std::regex_match(prop, std::regex("[-+]?\\d*\\.?\\d+([eE][-+]?\\d+)?")) || std::regex_match(prop, std::regex("\\d+"))) {
                global_rebuilt += prop + ",";
            } else {
                global_rebuilt += std::to_string(prop.length()) + "H" + prop + ",";
            }
        }
        global_rebuilt = std::regex_replace(global_rebuilt, std::regex(",$"), ";");
        // Pad and split into lines
        std::string global_lines;
        int seq = 1;
        for (size_t i = 0; i < global_rebuilt.length(); i += 72) {
            std::string chunk = global_rebuilt.substr(i, 72);
            chunk += std::string(72 - chunk.length(), ' ');
            std::ostringstream oss;
            oss << "G" << std::setw(7) << seq++;
            global_lines += chunk + oss.str() + "\n";
        }
        std::ofstream out(output_path);
        out << global_lines << other_content;
        out.close();
    }
};

// Example usage:
// int main() {
//     IGESParser parser;
//     parser.open_file("example.iges");
//     parser.decode_properties();
//     parser.print_properties();
//     parser.write_file("modified.iges");
//     return 0;
// }