Task 692: .STK File Format

Task 692: .STK File Format

File Format Specifications for .STK

The .STK file format, as used in RouterCiM software, is a text-based format for describing irregular stock profiles. It is identical to the .VEC format and contains comments, a header, and coordinate data for vertices.

1. List of Properties Intrinsic to the File Format

  • Comment lines (starting with '#'): Include software name, version, language, shape name, and other optional notes.
  • Header line: Identifier like '@ Vec not Compressed' to indicate the format and compression status.
  • Insertion point (x, y): The starting point for the shape.
  • Shape area: The calculated area of the shape.
  • Shape perimeter: The calculated perimeter of the shape.
  • Shape rectangle length: The length of the enclosing rectangle.
  • Shape rectangle width: The width of the enclosing rectangle.
  • Vertex list: A series of x, y coordinates for each vertex of the profile.
  • Bulge values: Optional, attached to starting vertices for arc segments.
  • Center point and radius: Optional, for profiles that are circles.

Note: Reliable direct downloads for RouterCiM .STK files were not found. The following are direct links to .STK files from Pivot Animator, which use a different (binary) .STK format, but they are valid .STK files.

3. Ghost Blog Embedded HTML JavaScript for Drag and Drop .STK File Dump

Drag and drop .STK file here

4. Python Class for .STK File

class STKFile:
    def __init__(self, filename):
        self.filename = filename
        self.comments = []
        self.header = None
        self.insertion_point = None
        self.area = None
        self.perimeter = None
        self.rect_length = None
        self.rect_width = None
        self.vertices = []
        self.read()

    def read(self):
        with open(self.filename, 'r') as f:
            lines = f.readlines()
        lines = [line.strip() for line in lines if line.strip()]
        self.comments = [line for line in lines if line.startsWith('#')]
        self.header = next((line for line in lines if line.startsWith('@')), None)
        data_lines = [line for line in lines if not line.startsWith('#') and not line.startsWith('@')]
        numbers = []
        for line in data_lines:
            numbers.extend(float(x) for x in line.split() if x)
        if len(numbers) >= 6:
            self.insertion_point = (numbers[0], numbers[1])
            self.area = numbers[2]
            self.perimeter = numbers[3]
            self.rect_length = numbers[4]
            self.rect_width = numbers[5]
            for i in range(6, len(numbers), 2):
                self.vertices.append((numbers[i], numbers[i+1]))

    def print_properties(self):
        print("Comments:")
        for c in self.comments:
            print(c)
        print("Header:", self.header)
        print("Insertion Point:", self.insertion_point)
        print("Area:", self.area)
        print("Perimeter:", self.perimeter)
        print("Rectangle Length:", self.rect_length)
        print("Rectangle Width:", self.rect_width)
        print("Vertices:")
        for v in self.vertices:
            print(v)

    def write(self, filename=None):
        if filename is None:
            filename = self.filename
        with open(filename, 'w') as f:
            for c in self.comments:
                f.write(c + '\n')
            if self.header:
                f.write(self.header + '\n')
            if self.insertion_point:
                f.write(f"{self.insertion_point[0]} {self.insertion_point[1]} {self.area} {self.perimeter} {self.rect_length} {self.rect_width}\n")
            for v in self.vertices:
                f.write(f"{v[0]} {v[1]}\n")

# Example usage
# stk = STKFile('example.stk')
# stk.print_properties()
# stk.write('output.stk')

5. Java Class for .STK File

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

public class STKFile {
    private String filename;
    private List<String> comments = new ArrayList<>();
    private String header;
    private double insertionX, insertionY;
    private double area;
    private double perimeter;
    private double rectLength, rectWidth;
    private List<double[]> vertices = new ArrayList<>();

    public STKFile(String filename) {
        this.filename = filename;
        read();
    }

    private void read() {
        try (BufferedReader br = new BufferedReader(new FileReader(filename))) {
            String line;
            List<String> dataLines = new ArrayList<>();
            while (line = br.readLine() != null) {
                line = line.trim();
                if (line.isEmpty()) continue;
                if (line.startsWith("#")) {
                    comments.add(line);
                } else if (line.startsWith("@")) {
                    header = line;
                } else {
                    dataLines.add(line);
                }
            }
            List<Double> numbers = new ArrayList<>();
            for (String dl : dataLines) {
                String[] parts = dl.split("\\s+");
                for (String p : parts) {
                    if (!p.isEmpty()) numbers.add(Double.parseDouble(p));
                }
            }
            if (numbers.size() >= 6) {
                insertionX = numbers.get(0);
                insertionY = numbers.get(1);
                area = numbers.get(2);
                perimeter = numbers.get(3);
                rectLength = numbers.get(4);
                rectWidth = numbers.get(5);
                for (int i = 6; i < numbers.size(); i += 2) {
                    vertices.add(new double[]{numbers.get(i), numbers.get(i+1)});
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void printProperties() {
        System.out.println("Comments:");
        for (String c : comments) {
            System.out.println(c);
        }
        System.out.println("Header: " + header);
        System.out.println("Insertion Point: (" + insertionX + ", " + insertionY + ")");
        System.out.println("Area: " + area);
        System.out.println("Perimeter: " + perimeter);
        System.out.println("Rectangle Length: " + rectLength);
        System.out.println("Rectangle Width: " + rectWidth);
        System.out.println("Vertices:");
        for (double[] v : vertices) {
            System.out.println("(" + v[0] + ", " + v[1] + ")");
        }
    }

    public void write(String filename) {
        try (PrintWriter pw = new PrintWriter(filename)) {
            for (String c : comments) {
                pw.println(c);
            }
            if (header != null) {
                pw.println(header);
            }
            pw.print(insertionX + " " + insertionY + " " + area + " " + perimeter + " " + rectLength + " " + rectWidth);
            pw.println();
            for (double[] v : vertices) {
                pw.println(v[0] + " " + v[1]);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // Example usage
    // public static void main(String[] args) {
    //     STKFile stk = new STKFile("example.stk");
    //     stk.printProperties();
    //     stk.write("output.stk");
    // }
}

6. JavaScript Class for .STK File

class STKFile {
  constructor(filename) {
    this.filename = filename;
    this.comments = [];
    this.header = null;
    this.insertionPoint = null;
    this.area = null;
    this.perimeter = null;
    this.rectLength = null;
    this.rectWidth = null;
    this.vertices = [];
    this.read(); // Note: JS can't read local files without FileReader, so this assumes async or server
  }

  async read() {
    // For console, assume fetch if server file
    const response = await fetch(this.filename);
    const text = await response.text();
    const lines = text.split('\n').map(l => l.trim()).filter(l => l);
    this.comments = lines.filter(l => l.startsWith('#'));
    this.header = lines.find(l => l.startsWith('@'));
    const dataLines = lines.filter(l => !l.startsWith('#') && !l.startsWith('@'));
    const numbers = dataLines.flatMap(l => l.split(/\s+/).map(Number).filter(n => !isNaN(n)));
    if (numbers.length >= 6) {
      this.insertionPoint = {x: numbers[0], y: numbers[1]};
      this.area = numbers[2];
      this.perimeter = numbers[3];
      this.rectLength = numbers[4];
      this.rectWidth = numbers[5];
      for (let i = 6; i < numbers.length; i += 2) {
        this.vertices.push({x: numbers[i], y: numbers[i+1]});
      }
    }
  }

  printProperties() {
    console.log('Comments:');
    this.comments.forEach(c => console.log(c));
    console.log('Header:', this.header);
    console.log('Insertion Point:', this.insertionPoint);
    console.log('Area:', this.area);
    console.log('Perimeter:', this.perimeter);
    console.log('Rectangle Length:', this.rectLength);
    console.log('Rectangle Width:', this.rectWidth);
    console.log('Vertices:');
    this.vertices.forEach(v => console.log(v));
  }

  write(filename) {
    let text = this.comments.join('\n') + '\n';
    if (this.header) text += this.header + '\n';
    if (this.insertionPoint) text += `${this.insertionPoint.x} ${this.insertionPoint.y} ${this.area} ${this.perimeter} ${this.rectLength} ${this.rectWidth}\n`;
    this.vertices.forEach(v => text += `${v.x} ${v.y}\n`);
    // For write, use Blob and download
    const blob = new Blob([text], {type: 'text/plain'});
    const a = document.createElement('a');
    a.href = URL.createObjectURL(blob);
    a.download = filename || this.filename;
    a.click();
  }
}

// Example usage
// const stk = new STKFile('example.stk');
 // await stk.read();
 // stk.printProperties();
 // stk.write('output.stk');

7. C Class for .STK File

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char **comments;
    int num_comments;
    char *header;
    double insertion_x, insertion_y;
    double area;
    double perimeter;
    double rect_length, rect_width;
    double *vertices_x;
    double *vertices_y;
    int num_vertices;
} STKFile;

STKFile *stk_open(const char *filename) {
    STKFile *stk = malloc(sizeof(STKFile));
    stk->comments = NULL;
    stk->num_comments = 0;
    stk->header = NULL;
    stk->vertices_x = NULL;
    stk->vertices_y = NULL;
    stk->num_vertices = 0;

    FILE *f = fopen(filename, "r");
    if (f == NULL) return NULL;

    char line[1024];
    double numbers[1024];
    int num_numbers = 0;

    while (fgets(line, sizeof(line), f)) {
        char *trim = line;
        while (*trim == ' ') trim++;
        if (*trim == 0) continue;

        if (*trim == '#') {
            stk->num_comments++;
            stk->comments = realloc(stk->comments, stk->num_comments * sizeof(char*));
            stk->comments[stk->num_comments - 1] = strdup(trim);
        } else if (*trim == '@') {
            stk->header = strdup(trim);
        } else {
            char *token = strtok(trim, " ");
            while (token) {
                numbers[num_numbers++] = atof(token);
                token = strtok(NULL, " ");
            }
        }
    }
    fclose(f);

    if (num_numbers >= 6) {
        stk->insertion_x = numbers[0];
        stk->insertion_y = numbers[1];
        stk->area = numbers[2];
        stk->perimeter = numbers[3];
        stk->rect_length = numbers[4];
        stk->rect_width = numbers[5];
        stk->num_vertices = (num_numbers - 6) / 2;
        stk->vertices_x = malloc(stk->num_vertices * sizeof(double));
        stk->vertices_y = malloc(stk->num_vertices * sizeof(double));
        for (int i = 0; i < stk->num_vertices; i++) {
            stk->vertices_x[i] = numbers[6 + i*2];
            stk->vertices_y[i] = numbers[6 + i*2 + 1];
        }
    }

    return stk;
}

void stk_print(STKFile *stk) {
    printf("Comments:\n");
    for (int i = 0; i < stk->num_comments; i++) {
        printf("%s\n", stk->comments[i]);
    }
    printf("Header: %s\n", stk->header);
    printf("Insertion Point: (%f, %f)\n", stk->insertion_x, stk->insertion_y);
    printf("Area: %f\n", stk->area);
    printf("Perimeter: %f\n", stk->perimeter);
    printf("Rectangle Length: %f\n", stk->rect_length);
    printf("Rectangle Width: %f\n", stk->rect_width);
    printf("Vertices:\n");
    for (int i = 0; i < stk->num_vertices; i++) {
        printf("(%f, %f)\n", stk->vertices_x[i], stk->vertices_y[i]);
    }
}

void stk_write(STKFile *stk, const char *filename) {
    FILE *f = fopen(filename, "w");
    if (f == NULL) return;

    for (int i = 0; i < stk->num_comments; i++) {
        fprintf(f, "%s\n", stk->comments[i]);
    }
    if (stk->header) fprintf(f, "%s\n", stk->header);
    fprintf(f, "%f %f %f %f %f %f\n", stk->insertion_x, stk->insertion_y, stk->area, stk->perimeter, stk->rect_length, stk->rect_width);
    for (int i = 0; i < stk->num_vertices; i++) {
        fprintf(f, "%f %f\n", stk->vertices_x[i], stk->vertices_y[i]);
    }

    fclose(f);
}

void stk_close(STKFile *stk) {
    for (int i = 0; i < stk->num_comments; i++) {
        free(stk->comments[i]);
    }
    free(stk->comments);
    free(stk->header);
    free(stk->vertices_x);
    free(stk->vertices_y);
    free(stk);
}

// Example usage
// int main() {
 //   STKFile *stk = stk_open("example.stk");
 //   stk_print(stk);
 //   stk_write(stk, "output.stk");
 //   stk_close(stk);
 //   return 0;
 // }