Skip to content

Commit

Permalink
feat(polydatanormals): add option to compute cell normals
Browse files Browse the repository at this point in the history
fix #2434
  • Loading branch information
finetjul committed Sep 17, 2023
1 parent 9af4da1 commit 7e224f7
Show file tree
Hide file tree
Showing 2 changed files with 132 additions and 29 deletions.
90 changes: 61 additions & 29 deletions Sources/Filters/Core/PolyDataNormals/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,24 @@ function vtkPolyDataNormals(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkPolyDataNormals');

publicAPI.vtkPolyDataNormalsExecute = (pointsData, polysData) => {
publicAPI.vtkPolyDataNormalsExecute = (
numberOfPolys,
polysData,
pointsData
) => {
if (!pointsData) {
return null;
}

const normalsData = new Float32Array(pointsData.length);
const pointNormals = new Float32Array(pointsData.length);
const cellNormals = new Float32Array(3 * numberOfPolys);
let cellNormalComponent = 0;

let numberOfPoints = 0;
const polysDataLength = polysData.length;

const cellPointIds = [0, 0, 0];
const cellNormal = [0, 0, 0];

for (let c = 0; c < polysDataLength; c += numberOfPoints + 1) {
numberOfPoints = polysData[c];
Expand All @@ -36,37 +43,46 @@ function vtkPolyDataNormals(publicAPI, model) {
cellPointIds[i - 1] = 3 * polysData[c + i];
}

const cellNormal = [];

vtkTriangle.computeNormal(
pointsData.slice(cellPointIds[0], cellPointIds[0] + 3),
pointsData.slice(cellPointIds[1], cellPointIds[1] + 3),
pointsData.slice(cellPointIds[2], cellPointIds[2] + 3),
cellNormal
);

for (let i = 1; i <= numberOfPoints; ++i) {
let pointId = 3 * polysData[c + i];
cellNormals[cellNormalComponent++] = cellNormal[0];
cellNormals[cellNormalComponent++] = cellNormal[1];
cellNormals[cellNormalComponent++] = cellNormal[2];

if (model.computePointNormals) {
for (let i = 1; i <= numberOfPoints; ++i) {
let pointId = 3 * polysData[c + i];

normalsData[pointId] += cellNormal[0];
normalsData[++pointId] += cellNormal[1];
normalsData[++pointId] += cellNormal[2];
pointNormals[pointId] += cellNormal[0];
pointNormals[++pointId] += cellNormal[1];
pointNormals[++pointId] += cellNormal[2];
}
}
}

/* Normalize normals */
// Normalize point normals.
// A point normal is the sum of all the cell normals the point belongs to
if (model.computePointNormals) {
const pointNormal = [0, 0, 0];
for (let i = 0; i < pointsData.length; ) {
pointNormal[0] = pointNormals[i];
pointNormal[1] = pointNormals[i + 1];
pointNormal[2] = pointNormals[i + 2];

for (let i = 0; i < pointsData.length; ) {
const pointNormal = normalsData.slice(i, i + 3);
vtkMath.normalize(pointNormal);

vtkMath.normalize(pointNormal);

normalsData[i++] = pointNormal[0];
normalsData[i++] = pointNormal[1];
normalsData[i++] = pointNormal[2];
pointNormals[i++] = pointNormal[0];
pointNormals[i++] = pointNormal[1];
pointNormals[i++] = pointNormal[2];
}
}

return normalsData;
return [cellNormals, pointNormals];
};

publicAPI.requestData = (inData, outData) => {
Expand All @@ -82,18 +98,8 @@ function vtkPolyDataNormals(publicAPI, model) {
return;
}

const outputNormalsData = publicAPI.vtkPolyDataNormalsExecute(
input.getPoints().getData(),
input.getPolys().getData()
);

const output = vtkPolyData.newInstance();

const outputNormals = vtkDataArray.newInstance({
numberOfComponents: 3,
values: outputNormalsData,
});

output.setPoints(input.getPoints());
output.setVerts(input.getVerts());
output.setLines(input.getLines());
Expand All @@ -104,7 +110,29 @@ function vtkPolyDataNormals(publicAPI, model) {
output.getCellData().passData(input.getCellData());
output.getFieldData().passData(input.getFieldData());

output.getPointData().setNormals(outputNormals);
const [cellNormals, pointNormals] = publicAPI.vtkPolyDataNormalsExecute(
input.getNumberOfPolys(),
input.getPolys().getData(),
input.getPoints().getData()
);

if (model.computePointNormals) {
const outputPointNormals = vtkDataArray.newInstance({
numberOfComponents: 3,
name: 'Normals',
values: pointNormals,
});
output.getPointData().setNormals(outputPointNormals);
}

if (model.computeCellNormals) {
const outputCellNormals = vtkDataArray.newInstance({
numberOfComponents: 3,
name: 'Normals',
values: cellNormals,
});
output.getCellData().setNormals(outputCellNormals);
}

outData[0] = output;
};
Expand All @@ -115,6 +143,8 @@ function vtkPolyDataNormals(publicAPI, model) {
// ----------------------------------------------------------------------------
function defaultValues(initialValues) {
return {
computeCellNormals: false,
computePointNormals: true,
...initialValues,
};
}
Expand All @@ -131,6 +161,8 @@ export function extend(publicAPI, model, initialValues = {}) {

macro.algo(publicAPI, model, 1, 1);

macro.setGet(publicAPI, model, ['computeCellNormals', 'computePointNormals']);

/* Object specific methods */

vtkPolyDataNormals(publicAPI, model);
Expand Down
71 changes: 71 additions & 0 deletions Sources/Filters/Core/PolyDataNormals/test/testPolyDataNormals.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import test from 'tape-catch';

import vtkCubeSource from 'vtk.js/Sources/Filters/Sources/CubeSource';
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
import vtkPolyDataNormals from 'vtk.js/Sources/Filters/Core/PolyDataNormals';
import vtkTriangle from 'vtk.js/Sources/Common/DataModel/Triangle';

const PRECISION = 4;

test('Test vtkPolyDataNormals passData', (t) => {
const cube = vtkCubeSource.newInstance();
Expand All @@ -24,3 +28,70 @@ test('Test vtkPolyDataNormals passData', (t) => {

t.end();
});

test.only('Test vtkPolyDataNormals normals', (t) => {
const cube = vtkCubeSource.newInstance();
const input = cube.getOutputData();
const pointNormalsData = input.getPointData().getNormals().getData();
// const cellNormalsData = input.getCellData().getNormals().getData();
input.getPointData().setNormals(null);
input.getCellData().setNormals(null);

const normals = vtkPolyDataNormals.newInstance();
normals.setInputData(input);
normals.setComputeCellNormals(true);
normals.update();
const output = normals.getOutputData();

console.log(pointNormalsData);
console.log(output.getPointData().getNormals().getData());
t.deepEqual(
vtkMath.roundVector(pointNormalsData, [], PRECISION),
vtkMath.roundVector(
output.getPointData().getNormals().getData(),
[],
PRECISION
),
'Same point normals'
);

const pointsData = output.getPoints().getData();
const polysData = output.getPolys().getData();
const polysDataLength = polysData.length;
const cellPointIds = [0, 0, 0];
let numberOfPoints = 0;
let polysId = 0;
for (let c = 0; c < polysDataLength; c += numberOfPoints + 1) {
numberOfPoints = polysData[c];

for (let i = 1; i <= 3; ++i) {
cellPointIds[i - 1] = 3 * polysData[c + i];
}

const cellNormal = [];

vtkTriangle.computeNormal(
pointsData.slice(cellPointIds[0], cellPointIds[0] + 3),
pointsData.slice(cellPointIds[1], cellPointIds[1] + 3),
pointsData.slice(cellPointIds[2], cellPointIds[2] + 3),
cellNormal
);

t.deepEqual(
vtkMath.roundVector(cellNormal, [], PRECISION),
vtkMath.roundVector(
output
.getCellData()
.getNormals()
.getData()
.slice(3 * polysId, 3 * polysId + 3),
[],
PRECISION
),
`Same cell normal #${polysId}`
);
++polysId;
}

t.end();
});

0 comments on commit 7e224f7

Please sign in to comment.