UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

201 lines (154 loc) 8.44 kB
import _defineProperty from '@babel/runtime/helpers/defineProperty'; import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray'; import macro from '../../macros.js'; import vtkCellArray from '../../Common/Core/CellArray.js'; import vtkPolygon from '../../Common/DataModel/Polygon.js'; import vtkPolyData from '../../Common/DataModel/PolyData.js'; import { VtkDataTypes } from '../../Common/Core/DataArray/Constants.js'; import { vtkCCSMakePolysFromLines, vtkCCSJoinLooseEnds, vtkCCSFindTrueEdges, vtkCCSMakeHoleyPolys, vtkCCSCutHoleyPolys, vtkCCSSplitAtPinchPoints, vtkCCSTriangulate } from './ContourTriangulator/helper.js'; function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } var vtkErrorMacro = macro.vtkErrorMacro; var TRIANGULATION_ERROR_DISPLAY = false; function triangulateContours(polyData, firstLine, numLines, polys, normal) { var triangulatePolys = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : true; var triangulationFailure = false; // If no cut lines were generated, there's nothing to do if (numLines <= 0) { return false; } var points = polyData.getPoints(); // Join all the new lines into connected groups, i.e. polygons. // If we are lucky these will be simple, convex polygons. But // we can't count on that. var newPolys = []; var incompletePolys = []; var oriented = normal != null; vtkCCSMakePolysFromLines(polyData, firstLine, firstLine + numLines, oriented, newPolys, incompletePolys); // if no normal specified, then compute one from largest contour var computedNormal = normal; if (normal == null) { var maxnorm = 0; var n = []; for (var i = 0; i < newPolys.length; i++) { var norm = vtkPolygon.getNormal(newPolys[i], points, n); if (norm > maxnorm) { maxnorm = norm; computedNormal[0] = n[0]; computedNormal[1] = n[1]; computedNormal[2] = n[2]; } } } // Join any loose ends. If the input was a closed surface then there // will not be any loose ends, so this is provided as a service to users // who want to clip a non-closed surface. vtkCCSJoinLooseEnds(newPolys, incompletePolys, points, computedNormal); // Some points might be in the middle of straight line segments. // These points can be removed without changing the shape of the // polys, and removing them makes triangulation more stable. // Unfortunately removing these points also means that the polys // will no longer form a watertight cap over the cut. var polyEdges = []; var originalEdges = []; vtkCCSFindTrueEdges(newPolys, points, polyEdges, originalEdges); // Next we have to check for polygons with holes, i.e. polygons that // have other polygons inside. Each polygon is "grouped" with the // polygons that make up its holes. // Initialize each group to hold just one polygon. var numNewPolys = newPolys.length; var polyGroups = []; for (var _i = 0; _i < numNewPolys; _i++) { polyGroups[_i] = [_i]; } // Find out which polys are holes in larger polys. Create a group // for each poly where the first member of the group is the larger // poly, and all other members are the holes. The number of polyGroups // will be the same as the number of polys, and any polys that are // holes will have a matching empty group. vtkCCSMakeHoleyPolys(newPolys, points, polyGroups, polyEdges, originalEdges, computedNormal, oriented); // Make cuts to create simple polygons out of the holey polys. // After this is done, each polyGroup will have exactly 1 polygon, // and no polys will be holes. This is currently the most computationally // expensive part of the process. if (!vtkCCSCutHoleyPolys(newPolys, points, polyGroups, polyEdges, computedNormal)) { triangulationFailure = true; } // Some polys might be self-intersecting. Split the polys at each intersection point. vtkCCSSplitAtPinchPoints(newPolys, points, polyGroups, polyEdges, computedNormal, oriented); // ------ Triangulation code ------ // Go through all polys and triangulate them for (var polyId = 0; polyId < polyGroups.length; polyId++) { // If group is empty, then poly was a hole without a containing poly if (polyGroups[polyId].length === 0) { // eslint-disable-next-line no-continue continue; } if (!triangulatePolys) { polys.insertNextCell(originalEdges.slice(1, originalEdges.length)); } else if (!vtkCCSTriangulate(newPolys[polyId], points, polyEdges[polyId], originalEdges, polys, computedNormal)) { triangulationFailure = false; // Diagnostic code: show the polys as outlines } } return !triangulationFailure; } // --------------------------------------------------- function triangulatePolygon(polygon, points, triangles) { var poly = _toConsumableArray(polygon); var polys = [poly]; var originalEdges = []; var polyEdges = []; vtkCCSFindTrueEdges(polys, points, polyEdges, originalEdges); var edges = polyEdges[0]; var success = true; var normal = []; var norm = vtkPolygon.getNormal(poly, points, normal); if (norm !== 0) { success = vtkCCSTriangulate(poly, points, edges, originalEdges, triangles, normal); } return success; } var STATIC = { triangulateContours: triangulateContours, triangulatePolygon: triangulatePolygon }; function vtkContourTriangulator(publicAPI, model) { // Set our className model.classHierarchy.push('vtkContourTriangulator'); publicAPI.requestData = function (inData, outData) { // implement requestData var input = inData[0]; var output = vtkPolyData.newInstance(); outData[0] = output; if (!input) { vtkErrorMacro('Invalid or missing input'); return false; } var triangulationError = false; var lines = input.getLines(); if (lines == null || lines.getNumberOfCells() === 0) { return true; } input.buildCells(); var polysArray = vtkCellArray.newInstance({ dataType: VtkDataTypes.DOUBLE, empty: true }); output.setPolys(polysArray); output.setPoints(input.getPoints()); output.getPointData().passData(input.getPointData()); triangulationError = !triangulateContours(input, input.getNumberOfVerts(), lines.getNumberOfCells(), polysArray, [], model.triangulatePolys); if (triangulationError && TRIANGULATION_ERROR_DISPLAY) { vtkErrorMacro('Triangulation failed, output might have holes.'); } return true; }; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- var DEFAULT_VALUES = { triangulatePolys: true }; // ---------------------------------------------------------------------------- function extend(publicAPI, model) { var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); // Make this a VTK object macro.obj(publicAPI, model); // Also make it an algorithm with one input and one output macro.algo(publicAPI, model, 1, 1); macro.setGet(publicAPI, model, ['triangulate']); // Object specific methods vtkContourTriangulator(publicAPI, model); } // ---------------------------------------------------------------------------- var newInstance = macro.newInstance(extend, 'vtkContourTriangulator'); // ---------------------------------------------------------------------------- var vtkContourTriangulator$1 = _objectSpread({ newInstance: newInstance, extend: extend }, STATIC); export { STATIC, vtkContourTriangulator$1 as default, extend, newInstance };