UNPKG

ducki

Version:

Simple utility scripts for exporting KiCad images.

154 lines (116 loc) 4.29 kB
import fs from "fs"; import { dirname, join, resolve as _resolve } from "path"; import { run } from "./run.js"; import { fileURLToPath } from 'node:url'; const __dirname = dirname(fileURLToPath(import.meta.url)); export function resolve(...path: Array<string>): string { return _resolve(__dirname, "..", ...path); } export interface RenderXYZ { x?: number, y?: number, z?: number } export interface RenderSize { height?: number, width?: number } export interface RenderOptions { perspective?: boolean, zoom?: number, pan?: RenderXYZ, rotate?: RenderXYZ, pivot?: RenderXYZ, size?: RenderSize } function flatXYZ(xyz?: RenderXYZ): string { if (xyz == null) { return "0,0,0"; } return "'" + [ String(xyz.x || 0), String(xyz.y || 0), String(xyz.z || 0), ].join(",") + "'"; } function normalizeSize(size?: RenderSize): { width: number, height: number } { if (size == null) { return { width: 512, height: 512 }; } let { width, height } = size; if (width != null) { if (height == null) { height = width; } } else if (height == null) { if (width == null) { width = height; } } if (width == null) { width = 512; } if (height == null) { height = 512; } return { width, height }; } function searchDir(folder: string, ext: string): Array<string> { ext = "." + ext; const result: Array<string> = [ ]; for (const filename of fs.readdirSync(folder)) { if (filename[0] !== "_" && filename[0] !== "." && filename.endsWith(ext)) { result.push(filename); } } return result; } export class Project { readonly cmd: string; readonly projectFolder: string; constructor(cmd: string, projectFolder: string) { this.cmd = resolve(cmd); this.projectFolder = projectFolder; } _searchDir(ext: string): Array<string> { return searchDir(this.projectFolder, ext); } get projectFilename(): string { const files = this._searchDir("kicad_pro"); if (files.length === 0 ) { throw new Error(`No project file found in ${ JSON.stringify(this.projectFolder)}`); } if (files.length > 1) { throw new Error(`Too many project files found in ${ JSON.stringify(this.projectFolder)}`); } return join(this.projectFolder, files[0]);; } get pcbFilename(): string { const files = this._searchDir("kicad_pcb"); if (files.length === 0 ) { throw new Error(`No PCB file found in ${ JSON.stringify(this.projectFolder)}`); } if (files.length > 1) { throw new Error(`Too many PCB files found in ${ JSON.stringify(this.projectFolder)}`); } return join(this.projectFolder, files[0]);; } render(options?: RenderOptions, filename?: string): void { if (options == null) { options = { }; } if (filename == null) { filename = "temp-output.png"; } filename = _resolve(this.projectFolder, filename); if (!filename.endsWith(".png") && !filename.endsWith(".jpg")) { throw new Error("Invalid image filename"); } console.log("GENERATING:", filename); const args: Array<string> = [ "pcb", "render", "--output", filename ]; if (options.perspective) { args.push("--perspective"); } if (options.zoom) { args.push("--zoom", String(options.zoom)); } if (options.pivot) { args.push("--pivot", flatXYZ(options.pivot)); } if (options.rotate) { args.push("--rotate", flatXYZ(options.rotate)); } if (options.pan) { args.push("--pan", flatXYZ(options.pan)); } const size = normalizeSize(options.size); args.push("--width", String(size.width)); args.push("--height", String(size.height)); args.push(this.pcbFilename); const result = run(this.cmd, args); if (result.stdout.indexOf("Successfully created 3D render image") === -1) { console.log({ args, status: result.status, stdout: result.stdout, stderr: result.stderr }); throw new Error("Failed to render PCB"); } } }