holes-in
Version:
Generates a 3D mesh from a 2D outer path and 2D inner paths
187 lines (157 loc) • 6.7 kB
JavaScript
;
const pathHelper = require("./path-helper.js");
const constants = require("./constants.js");
const uvHelper = {
/** ***********************************
First paradygm: map on vertival and horizontal independantly.
Don't care about discontinuities between vertical and horizontal.
***************************************/
mapHorizontal(pathsByDepth, outerShape, horizontalGeom, options) {
if (!horizontalGeom) { return; }
const points = horizontalGeom.points;
const boundaries = uvHelper.getBoundaries(pathsByDepth, outerShape, options);
uvHelper.setMinBoundaryHorr(outerShape, boundaries);
const uv = uvHelper.getUVHorFaces(pathsByDepth, outerShape, boundaries, points);
uvHelper.addUvToGeom(uv, horizontalGeom);
},
mapVertical(pathsByDepth, outerShape, options) {
// determine the interpolation function:
const boundaries = uvHelper.getBoundaries(pathsByDepth, outerShape, options);
// for each depth: constructs the uvs:
for (let depth = 0; depth < pathsByDepth.length; depth++) {
const pathsAtDepth = pathsByDepth[depth];
for (let i = 0; i < pathsAtDepth.paths.length; i++) {
uvHelper.getUVertPath(i, pathsByDepth, +depth, boundaries);
}
const v = uvHelper.interpolate(boundaries.boundary.Z, boundaries.boundaryTex.V, pathsAtDepth.depth * constants.scaleFactor);
pathsAtDepth.holesInV = v;
}
},
getUVHorFaces(pathsByDepth, outerShape, boundaries, points) {
if (points.length === 0) return;
const res = [];
for (let i = 0; i < points.length; i += 3) {
const point = points.slice(i, i + 3);
res.push(...uvHelper.getUVFromHorrPoint(boundaries, point));
}
return res;
},
getUVertPath(indPath, pathsByDepth, indexDepth, boundaries) {
const pathsAtDepth = pathsByDepth[indexDepth];
const path = pathsAtDepth.paths[indPath];
if (path.length === 0) return;
// finds into the upper paths if there is a matching edge
let match;
for (let i = indexDepth - 1; i >= 0; i--) {
for (let j = 0; j < pathsByDepth[i].paths.length; j++) {
const pathToMatch = pathsByDepth[i].paths[j];
match = pathHelper.getMatchingEdgeIndex(path, pathToMatch);
if (match) {
i = -1;
break;
}
}
}
const offset = { index: 0, distance: 0, u: 0 };
// if so, offsets it to keep a max of continuity belong Z
if (match) {
offset.distance = pathHelper.getDistance(path[match.index], match.pointmatch);
offset.index = match.index;
offset.u = match.pointmatch.holesInU;
}
// interpolates
uvHelper.interpolatePathU(path, boundaries, offset);
},
getMaxPathLength(pathsByDepth) {
let max = 0;
for (let i = 0; i < pathsByDepth.length; i++) {
max = Math.max(max, Math.max(pathHelper.getTotalLength(...pathsByDepth[i].paths)));
}
return max;
},
getUVFromHorrPoint(boundaries, point) {
const U = uvHelper.interpolateInv(boundaries.boundary.XY, boundaries.boundaryTex.U, point[0] * constants.scaleFactor);
const V = uvHelper.interpolate(boundaries.boundary.Z, boundaries.boundaryTex.V, point[1] * constants.scaleFactor);
return [U, V];
},
interpolatePathU(path, boundaries, offset) {
let dist = 0;
const startIndex = offset.index;
for (let i = startIndex; i < path.length + startIndex; i++) {
const valueU = (dist + offset.distance);
const u = uvHelper.interpolateInv(boundaries.boundary.XY, boundaries.boundaryTex.U, valueU);
path[i % path.length].holesInU = u;
dist += pathHelper.getDistance(path[i % path.length], path[(i + 1) % path.length]);
}
const valueU = (dist + offset.distance);
const u = uvHelper.interpolateInv(boundaries.boundary.XY, boundaries.boundaryTex.U, valueU);
path[startIndex].holesInU2 = u;
},
interpolate(boundarySrc, boundaryDst, value) {
return ((value - boundarySrc.min) / (boundarySrc.max - boundarySrc.min)) * (boundaryDst.max - boundaryDst.min) + boundaryDst.min;
},
interpolateInv(boundarySrc, boundaryDst, value) {
return (1.0 - (value - boundarySrc.min) / (boundarySrc.max - boundarySrc.min)) * (boundaryDst.max - boundaryDst.min) + boundaryDst.min;
},
addUvsToGeoms(uvs, geoms) {
for (let i = 0; i < geoms.length; i++) {
let uv = [];
if (geoms[i].uv) {
continue;
}
if (!uvs[i]) {
uv = Array(2 * geoms[i].points.length / 3);
}
geoms[i].uvs = uv;
}
},
addUvToGeom(uvs, geom) {
if (geom.uvs.length > 0) {
return;
}
if (!uvs || uvs.length === 0) { uvs = new Array(2 * geom.points.length / 3).fill(0); }
geom.uvs = uvs;
},
setMinBoundaryHorr(outerShape, boundaries) {
let minX = outerShape.path[0].X;
let minY = outerShape.path[0].Y;
for (let i = 1; i < outerShape.path.length; i++) {
const x = outerShape.path[i].X;
const y = outerShape.path[i].Y;
if (x < minX) minX = x;
if (y < minY) minY = y;
}
boundaries.boundary.XY.min += minX;
boundaries.boundary.Z.min += minY;
boundaries.boundary.XY.max += minX;
boundaries.boundary.Z.max += minY;
},
getBoundaries(pathsByDepth, outerShape, options) {
let maxLength = uvHelper.getMaxPathLength(pathsByDepth);
maxLength = Math.max(pathHelper.getTotalLength(outerShape.path));
const maxDepth = outerShape.depth;
const max = Math.max(maxLength, maxDepth);
const boundaryTex = { U: { min: 0, max: 1 }, V: { min: 0, max: 1 } };
const boundary = { XY: { min: 0, max }, Z: { min: 0, max } };
if (options.lengthU) {
boundary.XY.max = options.lengthU * constants.scaleFactor;
}
if (options.lengthV) {
boundary.Z.max = options.lengthV * constants.scaleFactor;
}
return { boundary, boundaryTex };
},
getO1BoudnaryTex() {
return {
X: {
min: 0,
max: 1,
},
Y: {
min: 0,
max: 1,
},
};
},
};
module.exports = uvHelper;