Вычислите ограничивающую рамку файла STL с помощью JavaScript

Итак, я использую этот пакет npm: node-stl

И он прекрасно работает. Однако синтаксис регулярного выражения, математика и геометрические вычисления меня несколько сбивают с толку. Особенно все одновременно.

В основном, чего я хочу добиться, так это расширить сценарий для вычисления ограничивающей рамки STL.

Вот основной файл, который вычисляет объем и вес анализируемого/читаемого STL.

var fs = require('fs');

// Vertex
function Vertex (v1,v2,v3) {
    this.v1 = Number(v1);
    this.v2 = Number(v2);
    this.v3 = Number(v3);
}

// Vertex Holder
function VertexHolder (vertex1,vertex2,vertex3) {
    this.vert1 = vertex1;
    this.vert2 = vertex2;
    this.vert3 = vertex3;
}

// transforming a Node.js Buffer into a V8 array buffer
function _toArrayBuffer (buffer) {
    var 
    ab = new ArrayBuffer(buffer.length),
    view = new Uint8Array(ab);

    for (var i = 0; i < buffer.length; ++i) {
        view[i] = buffer[i];
    }
    return ab;
}

// calculation of the triangle volume
// source: http://stackoverflow.com/questions/6518404/how-do-i-calculate-the-volume-of-an-object-stored-in-stl-files
function _triangleVolume (vertexHolder) {
    var 
    v321 = Number(vertexHolder.vert3.v1 * vertexHolder.vert2.v2 * vertexHolder.vert1.v3),
    v231 = Number(vertexHolder.vert2.v1 * vertexHolder.vert3.v2 * vertexHolder.vert1.v3),
    v312 = Number(vertexHolder.vert3.v1 * vertexHolder.vert1.v2 * vertexHolder.vert2.v3),
    v132 = Number(vertexHolder.vert1.v1 * vertexHolder.vert3.v2 * vertexHolder.vert2.v3),
    v213 = Number(vertexHolder.vert2.v1 * vertexHolder.vert1.v2 * vertexHolder.vert3.v3),
    v123 = Number(vertexHolder.vert1.v1 * vertexHolder.vert2.v2 * vertexHolder.vert3.v3);
    return Number(1.0/6.0)*(-v321 + v231 + v312 - v132 - v213 + v123);
}

// parsing an STL ASCII string
function _parseSTLString (stl) {
    var totalVol = 0;
    // yes, this is the regular expression, matching the vertexes
    // it was kind of tricky but it is fast and does the job
    var vertexes = stl.match(/facet\s+normal\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+outer\s+loop\s+vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+endloop\s+endfacet/g);

    vertexes.forEach(function (vert) {
        var preVertexHolder = new VertexHolder();
        vert.match(/vertex\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s+([-+]?\b(?:[0-9]*\.)?[0-9]+(?:[eE][-+]?[0-9]+)?\b)\s/g).forEach(function (vertex, i) {
            var tempVertex  = vertex.replace('vertex', '').match(/[-+]?[0-9]*\.?[0-9]+/g);
            var preVertex   = new Vertex(tempVertex[0],tempVertex[1],tempVertex[2]);
            preVertexHolder['vert'+(i+1)] = preVertex;
        });
        var partVolume = _triangleVolume(preVertexHolder);
        totalVol += Number(partVolume);
    })

    var volumeTotal = Math.abs(totalVol)/1000;
    return {
        volume: volumeTotal,        // cubic cm
        weight: volumeTotal * 1.04  // gm
    }
}

// parsing an STL Binary File
// (borrowed some code from here: https://github.com/mrdoob/three.js/blob/master/examples/js/loaders/STLLoader.js)
function _parseSTLBinary (buf) {
    buf = _toArrayBuffer(buf);

    var 
    headerLength    = 80,
    dataOffset      = 84,
    faceLength      = 12*4 + 2,
    le = true; // is little-endian

    var 
    dvTriangleCount = new DataView(buf, headerLength, 4),
    numTriangles    = dvTriangleCount.getUint32(0, le),
    totalVol        = 0;

    for (var i = 0; i < numTriangles; i++) {
        var 
        dv          = new DataView(buf, dataOffset + i*faceLength, faceLength),
        normal      = new Vertex(dv.getFloat32(0, le), dv.getFloat32(4, le), dv.getFloat32(8, le)),
        vertHolder  = new VertexHolder();
        for(var v = 3; v < 12; v+=3) {
            var vert = new Vertex(dv.getFloat32(v*4, le), dv.getFloat32((v+1)*4, le), dv.getFloat32( (v+2)*4, le ) );
            vertHolder['vert'+(v/3)] = vert;
        }
        totalVol += _triangleVolume(vertHolder);
    }

    var volumeTotal = Math.abs(totalVol)/1000;
    return {
        volume: volumeTotal,        // cubic cm
        weight: volumeTotal * 1.04  // gm
    }
}

// NodeStl
// =======
// > var stl = NodeStl(__dirname + '/myCool.stl');
// > console.log(stl.volume + 'cm^3');
// > console.log(stl.weight + 'gm');
function NodeStl (stlPath) {
    var 
    buf = fs.readFileSync(stlPath),
    isAscii = true;

    for (var i=0, len=buf.length; i<len; i++) {
        if (buf[i] > 127) { isAscii=false; break; }
    }

    if (isAscii)
        return _parseSTLString(buf.toString());
    else
        return _parseSTLBinary(buf);
}

module.exports = NodeStl;

Если бы кто-нибудь мог помочь мне с этим, было бы здорово. Я знаю, и мне кажется, что это просто. Что мне просто нужно знать max/min разных направлений (x, y, z), а затем вычислить ограничивающую рамку.

Но я не понимаю, что такое max/min для x, y и z. Пожалуйста, ответьте, если у вас есть идея.


person Aman    schedule 06.06.2016    source источник


Ответы (1)


Я создал новую ветку https://github.com/johannesboyne/node-stl/tree/boundingbox не могли бы вы проверить, работает ли примененный алгоритм?

Бест, Йоханнес

Редактировать: если ветка стабильна -> работает, я добавлю ее в версию 0.1.0 (не знаю, почему она до сих пор 0.0.1)

person johannesboyne    schedule 07.06.2016
comment
Большое спасибо!! Я использовал этот файл stl: thingiverse.com/thing:1607628 В качестве примера. В Cura и других онлайн-сайтах с парсерами STL я последовательно получил следующее (предполагая, что я выбрал мм): 6 см по x (длина) 4,5 см по y (ширина) 5 см по z (высота). . Аналогично: thingiverse.com/thing:972317 В сантиметрах: 7,62 x / 7,62 y / 13,6 z - person Aman; 07.06.2016
comment
Так что в принципе это не работает, эти STL дали мне разные числа с примененным алгоритмом. - person Aman; 07.06.2016
comment
Да! Извините, мое решение было дерьмом! :D Я нашел лучшее решение! 2 мин! - person johannesboyne; 07.06.2016
comment
Проверьте еще раз, пожалуйста! В моей системе и для петозавров я получаю хорошие результаты. - person johannesboyne; 07.06.2016
comment
УХ ТЫ! Это точно. Большое спасибо! Есть ли у вас курсы/руководства/книги, которые можно порекомендовать, чтобы лучше понять это? Я имею в виду как регулярное выражение, так и разбор 3d-моделей. - person Aman; 07.06.2016
comment
Извините, математика - это все знание Википедии, а регулярное выражение - это просто пробы и ошибки, плюс опыт работы с другими запросами регулярных выражений раньше и некоторые поиски в Google ... Я даже не уверен, нашел ли я его части в какой-то другой библиотеке. Вы также можете принять ответ, чтобы другие лучше нашли его решенным. - person johannesboyne; 08.06.2016