Andrei 2021-05-19 13:07:18 +03:00
parent b8d5db01b9
commit 3db8214819
5 changed files with 76 additions and 33 deletions

View File

@ -4,14 +4,14 @@
# (c) andreika <prometheus.pcb@gmail.com>
############################################################################################
import os, sys, re
import os, sys, re, math
import configparser
import gzip
### Unfortunately PyVRML97 (vrml.vrml97) is not capable of properly processing Altium-exported VRML-files...
if len(sys.argv) < 3:
print "Error! Please specify the place+board files and vrml filename."
print ("Error! Please specify the place+board files and vrml filename.")
sys.exit(1)
mergePlaceFile = sys.argv[1]
mergeBoardFile = sys.argv[2]
@ -32,42 +32,57 @@ with open(mergePlaceFile, 'rb') as fmp:
m = {"name": name, "x": m[1], "y": m[2], "rot": rot, "path": config[name]["Prefix"] }
fragments.append(m)
print "* Starting merge of " + str(len(fragments)) + " board fragments..."
print ("* Starting merge of " + str(len(fragments)) + " board fragments...")
outf = gzip.open(fileOutName, 'wb')
outf.write("#VRML V2.0 utf8\n")
pat_hdr = re.compile('^#VRML.*')
pat_idx = re.compile(r'(DEF|USE)\s+(Shape|_)(\w)')
pat_trans = re.compile(r'(translation)\s+([+\-0-9\.]+)\s+([+\-0-9\.]+)')
def trans_repl(m):
x = float(m.group(2))
y = float(m.group(3))
return m.group(1) + " " + str(x + off_x_mm) + " " + str(y + off_y_mm)
pat_kicad_transform = re.compile(r'DEF\s+(\w+)\s+Transform.*')
fId = 1
for frag in fragments:
# convert to mm
off_x_mm = float(frag["x"]) * 25.4
off_y_mm = float(frag["y"]) * 25.4
# todo: apply module rotations
rot = float(frag["rot"])
fileName = frag["path"] + "-vrml.wrl"
print "* Adding " + frag["name"] + " (" + fileName + ") at (" + str(off_x_mm) + "," + str(off_y_mm) + "), rot=" + str(rot) + "..."
z_offset = 0
was_global_transform = False
fragId = str(fId).zfill(2)
print ("* Adding " + frag["name"] + " (" + fileName + ") at (" + str(off_x_mm) + "," + str(off_y_mm) + "), rot=" + str(rot) + "...")
with open(fileName, 'rb') as f:
for line in f:
line = line.rstrip()
# skip the headers (we write our own because there should be only 1 header)
if pat_hdr.match(line):
continue
fragId = str(fId).zfill(2)
# add global transformation for the module
if not was_global_transform:
# for bottom-aligned kicad VRML files, we need to shift them down - to align it with the top surface of the board
if pat_kicad_transform.match(line):
print ("* Kicad VRML detected!")
# the board is 1.6 mm thick?
# todo: this is a 'hack'
z_offset = -1.6
outf.write("DEF TX" + frag["name"] + " Transform {\n")
outf.write(" center 0 0 0\n")
outf.write(" rotation 0 0 1 " + str(math.radians(rot)) + "\n")
outf.write(" scale 1.0 1.0 1.0\n")
outf.write(" scaleOrientation 0 0 1 0\n")
outf.write(" translation " + str(off_x_mm) + " " + str(off_y_mm) + " " + str(z_offset) + "\n")
outf.write(" children [\n")
was_global_transform = True
line = pat_idx.sub(r'\g<1> \g<2>' + fragId + '\g<3>', line)
line = pat_trans.sub(trans_repl, line)
outf.write(line + "\n")
f.close()
if was_global_transform:
outf.write("] }\n")
fId = fId + 1
outf.close()
print "Done!"
print ("Done!")

View File

@ -341,7 +341,6 @@ subprocess.call([sys.executable, "bin/create_3d_components.py",
board_cfg_path,
board_misc_path_name + "-3D.wrl.gz"])
"""
print ("Rendering a 3D-model of the board components...")
subprocess.call([node_bin, "bin/render_vrml/render_components.js",
board_misc_path_name + "-3D.wrl.gz",
@ -369,7 +368,6 @@ subprocess.call([sys.executable, "bin/gen_iBOM.py",
"./ibom-data",
rotations,
board_path_name + "-ibom.html"])
"""
print ("Cleaning up...")
delete_file(board_cfg_path)

View File

@ -20,7 +20,7 @@ function createBoardImg(pcbImg, outlineImg, compImg) {
var boardImg = new PNG({
width: Math.max(pcbImg.width, outlineImg.width, compImg.width),
height: Math.max(pcbImg.height, outlineImg.height, compImg.height) });
var pcbOffY = (pcbImg.height < boardImg.height) ? -(boardImg.height - pcbImg.height) : 0;
var pcbOffY = (pcbImg.height < outlineImg.height) ? -(outlineImg.height - pcbImg.height) : 0;
// Blit the pcbImg using the outlineImg mask and add compImg.
// We cannot use PNG.bitblt() for that
for (var y = 0; y < boardImg.height; y++) {

View File

@ -27,24 +27,31 @@ try {
var compImgFile = args[1];
var dpi = parseFloat(args[2]);
console.log("* Starting Puppeteer (" + vrmlFile + " dpi=" + dpi + "...");
console.log("* Starting Puppeteer (" + vrmlFile + " dpi=" + dpi + ")...");
(async () => {
const browser = await puppeteer.launch();
const browser = await puppeteer.launch({
timeout: 60000,
slowMo: 500,
headless: true,
args: ['--unlimited-storage', '--full-memory-crash-report']
});
const page = await browser.newPage();
var contentHtml = fs.readFileSync("bin/render_vrml/render_vrml.html", "utf8");
console.log("* Reading the input file...");
var vrmlData = fs.readFileSync(vrmlFile);
console.log("* Reading the input file...");
var vrmlData = fs.readFileSync(vrmlFile);
var vrmlDataType = "octet-stream";
if (vrmlFile.endsWith('.gz')) {
vrmlData = zlib.gunzipSync(vrmlData);
// we unzip it later, on the frontend side
vrmlDataType = "x-gzip";
}
var vrmlDataBase64 = vrmlData.toString("base64");
var vrmlDataBase64 = vrmlData.toString("base64");
// injecting the data to the client script
contentHtml = contentHtml.replace("___SCREEN_DPI___", dpi);
contentHtml = contentHtml.replace("___VRML_DATA___", "data:application/gzip;base64," + vrmlDataBase64);
// injecting the data to the client script
contentHtml = contentHtml.replace("___SCREEN_DPI___", dpi);
contentHtml = contentHtml.replace("___VRML_DATA___", "data:application/" + vrmlDataType + ";base64," + vrmlDataBase64);
page.on("console", message => {
message.args().forEach(async (arg) => {
@ -59,12 +66,19 @@ try {
})
.on("pageerror", ({ message }) => console.log(`* LOG_ERROR: ` + message))
.on("response", response => console.log(`* Loading: ` + `${response.status()} ${response.url()}`))
.on("requestfailed", request => console.log(`* Loading Failed: ` + `${request.failure().errorText} ${request.url()}`));
.on("requestfailed", request => console.log(`* Loading Failed: ` + `${request.failure() ? request.failure().errorText : "?"} ${request.url()}`));
console.log("* Executing the script...");
await page.setContent(contentHtml);
process.on('unhandledRejection', (reason, p) => {
console.error('Unhandled Rejection at: Promise', p, 'reason:', reason);
browser.close();
});
await page.setDefaultNavigationTimeout(90000); // 90 seconds
console.log("* Executing the script (content size is " + contentHtml.length + " bytes)...");
await page.setContent(contentHtml, { waitUntil: 'domcontentloaded' });
console.log("* Waiting for completion...");
const watchDog = page.waitForFunction("document.done");
const watchDog = page.waitForFunction("document.done", {timeout: 180000}); // 180 seconds
await watchDog;
var screenWidth = await page.evaluate(() => document.compImgWidth);
@ -72,6 +86,7 @@ try {
console.log("* Saving the screenshot (" + screenWidth + "x" + screenHeight + ")");
await page.setViewport({width: screenWidth, height: screenHeight, deviceScaleFactor: 1, });
await page.screenshot({path: compImgFile, omitBackground: true});
await page.close();
await browser.close();
console.log("* Done! Exiting...");
})();

View File

@ -21,12 +21,16 @@ var dist = 100;
var minDist = 0.001;
// the far clipping plane is intentionally set to be less than the dist - to clip the board surface!
var boardSurfaceClippingThreshold = 0.0001;
var boardSurfaceClippingThreshold = 0.001;
var gzHeader = "data:application/x-gzip;base64,";
// use the official Three.js public distribution
import * as THREE from 'https://unpkg.com/three@0.119.0/build/three.module.js';
import { VRMLLoader } from 'https://unpkg.com/three@0.119.0/examples/jsm/loaders/VRMLLoader.js';
import * as fflate from 'https://unpkg.com/three@0.128.0/examples/jsm/libs/fflate.module.js';
console.log('Starting...');
// this var is checked by the parent Node.js script
@ -39,6 +43,18 @@ var renderer;
function load() {
return new Promise((resolve, reject) => {
if (vrmlData.substring(0, gzHeader.length) === gzHeader) {
console.log('Decompressing GZip...');
vrmlData = vrmlData.substring(gzHeader.length);
var vrmlDataBytes = fflate.strToU8(atob(vrmlData), true);
var vrmlDataUncompressed = fflate.gunzipSync(vrmlDataBytes);
var vrmlDataUncompressedB64 = btoa(fflate.strFromU8(vrmlDataUncompressed));
vrmlData = "data:application/octet-stream;base64," + vrmlDataUncompressedB64;
console.log('Decompressed ' + vrmlDataUncompressed.length + ' bytes...');
}
console.log('Loading VRML...');
var loader = new VRMLLoader();
loader.load(vrmlData, function (object) {
console.log('Scene and camera setup...');
@ -78,11 +94,10 @@ function load() {
async function run() {
console.log('Init renderer...');
renderer = new THREE.WebGLRenderer({antialias: true, alpha: true, preserveDrawingBuffer: true});
renderer = new THREE.WebGLRenderer({antialias: true, alpha: true, logarithmicDepthBuffer: true, preserveDrawingBuffer: true});
renderer.setClearColor(0x000000, 0);
document.body.appendChild(renderer.domElement);
console.log('Loading VRML...');
await load();
console.log('Exiting script...');
}