Created
February 13, 2020 18:04
-
-
Save nkint/101bd30bbb06745dfc1d3d4a23564406 to your computer and use it in GitHub Desktop.
fitIntoBounds3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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