Skip to content

Instantly share code, notes, and snippets.

@nkint
Created February 13, 2020 18:04
Show Gist options
  • Save nkint/101bd30bbb06745dfc1d3d4a23564406 to your computer and use it in GitHub Desktop.
Save nkint/101bd30bbb06745dfc1d3d4a23564406 to your computer and use it in GitHub Desktop.
fitIntoBounds3
// 3d version of the 2d fitIntoBounds2
// https://github.com/thi-ng/umbrella/blob/feaf8d3f8c1dd3e9141a151b4e473423a6f62242/packages/geom/src/ops/fit-into-bounds.ts#L34
import { Vec, MAX3, MIN3, ReadonlyVec, neg, div4, div3, abs3, sub3, dist3 } from '@thi.ng/vectors';
import { concat, translation44, ReadonlyMat, scale44, mulV344 } from '@thi.ng/matrices';
import { bounds, centroid } from '@thi.ng/geom-poly-utils';
import { isArray, isNull } from '@thi.ng/checks';
/**
* Transform an array of 3d points by a 4x4 matrix.
*
* @param out
* @param pts
* @param mat
* @returns out
*/
function transformV344(out: Vec[], pts: ReadonlyVec[], mat: ReadonlyMat) {
if (isNull(out)) {
out = pts;
}
if (isArray(out) && out.length === 0) {
out = pts.map(_ => [0, 0, 0]);
}
if (!isArray(out)) {
throw new Error('transform3 out must me an array or null');
}
if (isArray(out) && out.length !== pts.length) {
throw new Error(`transform3: out must be an array with the the same length of input array`);
}
pts.forEach((point, i) => mulV344(out[i], mat, point));
return out;
}
const translateScale3 = (
out: Vec[],
pts: Vec[],
c1: ReadonlyVec,
c2: ReadonlyVec,
scaleMat: ReadonlyMat,
) =>
/* prettier-ignore */
transformV344(
out,
pts,
concat(
translation44([], c1),
scaleMat,
translation44([], c2)
)
);
/**
* Fit a 3d point array into a 3d bounding box.
*
* @example
* ```
* const positions = [ [-1, 1, 1], [1, 1, 1] ]
* fitIntoBounds3(null, positions, [
* [-8, -8, -8],
* [8, 8, 8],
* ]);
* ```
*
* @param out
* @param pts
* @param dest
*/
const fitIntoBounds3 = (out: Vec[], pts: Vec[], dest: Vec[]) => {
const src = bounds(pts, [...MAX3], [...MIN3]);
if (!src) return;
const c = centroid(src);
if (!c) return;
/* prettier-ignore */
const destSize = abs3(
[],
[
dest[0][0] - dest[1][0],
dest[0][1] - dest[1][1],
dest[0][2] - dest[1][2],
])
/* prettier-ignore */
const srcSize = abs3(
[],
[
src[0][0] - src[1][0],
src[0][1] - src[1][1],
src[0][2] - src[1][2],
])
const tscale = div3([], destSize, srcSize);
return translateScale3(out, pts, centroid(dest)!, neg(null, c), scale44([], tscale));
};
/*
######## ######## ###### ########
## ## ## ## ##
## ## ## ##
## ###### ###### ##
## ## ## ##
## ## ## ## ##
## ######## ###### ##
*/
const positions = [
[-1, 1, 1],
[1, 1, 1],
/* NOTE: with a translation should works the same */
// [4 + -1, 4 + 1, 4 + 1],
// [4 + 1, 4 + 1, 4 + 1],
];
const positionsFit = fitIntoBounds3([], positions, [
[-8, -8, -8],
[8, 8, 8],
]);
/* NOTE: should be [-8, 8, 8], [8, 8, 8] */
console.log({ positionsFit });
/* NOTE: works perfectly */
const icosahedron = [
[0, 0, 1.176],
[1.051, 0, 0.526],
[0.324, 1, 0.525],
[-0.851, 0.618, 0.526],
[-0.851, -0.618, 0.526],
[0.325, -1, 0.526],
[0.851, 0.618, -0.526],
[0.851, -0.618, -0.526],
[-0.325, 1, -0.526],
[-1.051, 0, -0.526],
[-0.325, -1, -0.526],
[0, 0, -1.176],
]
const icosahedronFit = fitIntoBounds3([], icosahedron, [
[-8, -8, -8],
[8, 8, 8],
]);
const icosahedronFitBounds = bounds(icosahedronFit, [...MAX3], [...MIN3])
console.log({icosahedronFit, icosahedronFitBounds})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment