grid-apps-cmms/src.old/geo/points.js

138 lines
4.1 KiB
JavaScript

/** Copyright Stewart Allen <sa@grid.space> -- All Rights Reserved */
"use strict";
// dep: geo.base
// dep: geo.point
gapp.register("geo.points", [], (root, exports) => {
const { base } = root;
const { config } = base;
gapp.overlay(base, {
verticesToPoints,
pointsToVertices
});
/**
* converts a geometry point array into a kiri point array
* with optional decimation
*/
function verticesToPoints(array, options) {
let parr = new Array(array.length / 3),
i = 0,
j = 0,
t = Date.now(),
hash = {},
unique = 0,
passes = 0,
points,
oldpoints = parr.length,
newpoints;
let {threshold, precision, maxpass} = options || {};
// threshold = point count for triggering decimation
// precision = under which points are merged
// maxpass = max number of decimations
threshold = threshold > 0 ? threshold : config.decimate_threshold;
precision = precision >= 0 ? precision : config.precision_decimate;
maxpass = maxpass >= 0 ? maxpass : 0;
// replace point objects with their equivalents
if (maxpass) {
while (i < array.length) {
let p = base.newPoint(array[i++], array[i++], array[i++]),
k = p.key,
m = hash[k];
if (!m) {
m = p;
hash[k] = p;
unique++;
}
parr[j++] = m;
}
} else {
while (i < array.length) {
parr[j++] = base.newPoint(array[i++], array[i++], array[i++]);
}
}
// decimate until all point spacing > precision
if (maxpass && precision > 0.0)
while (parr.length > threshold) {
let lines = [], line, dec = 0;
for (i=0; i<oldpoints; ) {
let p1 = parr[i++],
p2 = parr[i++],
p3 = parr[i++];
lines.push( {p1:p1, p2:p2, d:Math.sqrt(p1.distToSq3D(p2))} );
lines.push( {p1:p1, p2:p3, d:Math.sqrt(p1.distToSq3D(p3))} );
lines.push( {p1:p2, p2:p3, d:Math.sqrt(p2.distToSq3D(p3))} );
}
// sort by ascending line length
lines.sort(function(a,b) {
return a.d - b.d
});
// create offset mid-points
for (i=0; i<lines.length; i++) {
line = lines[i];
// skip lines longer than precision threshold
if (line.d >= precision) break;
// skip lines where one of the points is already offset
if (line.p1.op || line.p2.op) continue;
// todo skip dropping lines where either point is a "sharp" on 3 vectors
// todo skip dropping lines where either point connects to a "long" line
line.p1.op = line.p2.op = line.p1.midPointTo3D(line.p2);
dec++;
}
// exit if nothing to decimate
if (dec === 0) break;
passes++;
// create new facets
points = new Array(oldpoints);
newpoints = 0;
for (i=0; i<oldpoints; ) {
let p1 = parr[i++],
p2 = parr[i++],
p3 = parr[i++];
// drop facets with two offset points
if (p1.op && p1.op === p2.op) continue;
if (p1.op && p1.op === p3.op) continue;
if (p2.op && p2.op === p3.op) continue;
// otherwise emit altered facet
points[newpoints++] = p1.op || p1;
points[newpoints++] = p2.op || p2;
points[newpoints++] = p3.op || p3;
}
parr = points.slice(0,newpoints);
oldpoints = newpoints;
if (passes >= maxpass) {
break;
}
}
// if (passes) console.trace({passes, threshold, precision, maxpass});
if (passes) console.log({
before: array.length / 3,
after: parr.length,
unique: unique,
decimations: passes,
time: (Date.now() - t)
});
return parr;
}
function pointsToVertices(points) {
let vertices = new Float32Array(points.length * 3),
i = 0, vi = 0;
while (i < points.length) {
vertices[vi++] = points[i].x;
vertices[vi++] = points[i].y;
vertices[vi++] = points[i++].z;
}
return vertices;
}
});