// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause /** * @class vtkImprintFilter * @brief Imprint the contact surface of one object onto another surface * * This filter imprints the contact surface of one vtkPolyData mesh onto * a second, input vtkPolyData mesh. There are two inputs to the filter: * the target, which is the surface to be imprinted, and the imprint, which * is the object imprinting the target. * * A high level overview of the algorithm is as follows. 1) The target cells * are segregated into two subsets: those that may intersect the imprint * surface (the candidate cells determined by bounding box checks), and those * that do not. 2) The non-candidates are sent to the output, the candidate * intersection cells are further processed - eventually they will be * triangulated as a result of contact with the imprint, with the result of * the triangulation appended to the output. 3) The imprint points are projected * onto the candidate cells, determining a classification (on a target point, * on a target edge, interior to a target cell, outside the target). 4) The * non-outside imprint points are associated with one or more target cells. * 5) The imprint edges are intersected with the target cell edges, producing * additional points associated with the the candidate cells, as well as * "fragments" or portions of edges associated with the candidate target * cells. 6) On a per-candidate-target-cell basis, the points and edge * fragments associated with that cell are used to triangulate the cell. * 7) Finally, the triangulated target cells are appended to the output. * * Several options exist to specify how to produce an output cell data array * that indicates whether the output cells are in the imprinted area. If * enabled, this output vtkSignedCharArray will have a value=1 for cells that * are in the imprinted area. Otherwise, the value=0 is indicating the cell * is not in contact with the imprinted area. The name of this cell data * array is "ImprintedCells". * * The filter also has the option to pass through and generate point and cell * data. If PassCellData is enabled, then the cell data associated with the * cropped cells, or cells passed through from the input mesh, are passed * through to the output. If PassPointData is enabled, then in similar * fashion the point data is passed through; however new points generated by * intersection may have point data interpolated in one of two ways. First, * the target mesh edges are interpolated at the new intersection points to * generate point data, or the imprint edges are interpolated at the new * intersection points to generate point data. Note: for PassPointData and * point interpolation to function, the filter requires that the point data * attributes (from the target mesh and imprint mesh) are exactly the * same. If they are not, then a set intersection operation is performed that * uses the point data arrays common to both the target and imprint meshes. * * Some notes: * -- The algorithm assumes that the input target and imprint cells are convex. * -- If performing a PROJECTED_IMPRINT, the output is the imprint mesh with * the point coordinates modified by projecting the imprint points onto * the target. If the projection of an imprint point onto the target is * unsuccessful, the imprint point coordinates are not modified. * -- If performing a MERGED_IMPRINT, the number of output points is * (numTargetPts + numImprintPts + numEdgeIntPts). * -- Not all of the output points may be used, for example if an imprint point * is coincident (within the tolerance) of a target point, the target point * replaces the imprint point. * -- Candidate cells which may reside within the bounding box of the imprint * but may not actually intersect the imprint will be appended to the output * without triangulation. * -- Candidate cells that are intersected will be triangulated: i.e., triangles * will be produced and appended to the output. * -- Triangulation requires combining the points and edge fragments associated * with each target candidate cell, as well as the candidate cell's defining * points and edges, to produce the final triangulation. * -- Portions of the algorithm are SMP threaded. For example, steps #1 and #2 * (candidate segregation); point projection step #3; cell triangulation * step #6. Future implementations may further parallelize the algorithm. * -- The algorithm produces an output cell data array that indicates * which output cells are in the imprinted area. This vtkSignedCharArray * has a value=0 for cells that were originally target cells; a value=2 * for output cells that are in the imprinted region; and a value=1 for * cells that are in the transition region (between target and imprinted * cells). The name of this cell data array is "ImprintedCells". * */ #ifndef vtkImprintFilter_h #define vtkImprintFilter_h #include "vtkFiltersModelingModule.h" // For export macro #include "vtkPolyDataAlgorithm.h" VTK_ABI_NAMESPACE_BEGIN class vtkStaticCellLocator; class VTKFILTERSMODELING_EXPORT vtkImprintFilter : public vtkPolyDataAlgorithm { public: ///@{ /** * Standard methods to instantiate, print and provide type information. */ static vtkImprintFilter* New(); vtkTypeMacro(vtkImprintFilter, vtkPolyDataAlgorithm); void PrintSelf(ostream& os, vtkIndent indent) override; ///@} /** * Specify the first vtkPolyData input connection which defines the * surface mesh to imprint (i.e., the target). */ void SetTargetConnection(vtkAlgorithmOutput* algOutput); vtkAlgorithmOutput* GetTargetConnection(); ///@{ /** * Specify the first vtkPolyData input which defines the surface mesh to * imprint (i.e., the target). The imprint surface is provided by the * second input. */ void SetTargetData(vtkDataObject* target); vtkDataObject* GetTarget(); ///@} /** * Specify the a second vtkPolyData input connection which defines the * surface mesh with which to imprint the target (the target is provided by * the first input). */ void SetImprintConnection(vtkAlgorithmOutput* algOutput); vtkAlgorithmOutput* GetImprintConnection(); ///@{ /** * Specify the a second vtkPolyData input which defines the surface mesh * with which to imprint the target (i.e., the first input). */ void SetImprintData(vtkDataObject* imprint); vtkDataObject* GetImprint(); ///@} ///@{ /** * Specify a projection tolerance which controls how close the imprint * surface must be to the target to successfully imprint the surface. This * is an absolute value. */ vtkSetClampMacro(Tolerance, double, 0.0, VTK_FLOAT_MAX); vtkGetMacro(Tolerance, double); ///@} // Used to control how the merge tolerance value is interpreted. // ABSOLUTE_TOLERANCE is a tolerance expressed in world coordinates; // RELATIVE_TO_TOLERANCE is a tolerance relative to the projection // tolerance (i.e., MergeTolerance is a scale factor on Tolerance); // RELATIVE_TO_MIN_EDGE_LENGTH is a tolerance relative to the minimum edge // length of the tool/imprint mesh; and RELATIVE_TO_AVERAGE_EDGE_LENGTH is // a tolerance based on the average edge length of all imprint mesh edges. enum MergeTolType { ABSOLUTE_TOLERANCE = 0, RELATIVE_TO_PROJECTION_TOLERANCE = 1, RELATIVE_TO_MIN_EDGE_LENGTH = 2, RELATIVE_TO_AVERAGE_EDGE_LENGTH = 3 }; ///@{ /** * Specify a tolerance which is used to determine whether two points are * considered coincident to one another. This is important when performing * intersections and projections to reduce numerical issues. */ vtkSetClampMacro(MergeToleranceType, int, ABSOLUTE_TOLERANCE, RELATIVE_TO_AVERAGE_EDGE_LENGTH); vtkGetMacro(MergeToleranceType, int); void SetMergeToleranceTypeToAbsolute() { this->SetMergeToleranceType(ABSOLUTE_TOLERANCE); } void SetMergeToleranceTypeToRelativeToProjection() { this->SetMergeToleranceType(RELATIVE_TO_PROJECTION_TOLERANCE); } void SetMergeToleranceTypeToMinEdge() { this->SetMergeToleranceType(RELATIVE_TO_MIN_EDGE_LENGTH); } void SetMergeToleranceTypeToAverageEdge() { this->SetMergeToleranceType(RELATIVE_TO_AVERAGE_EDGE_LENGTH); } vtkSetClampMacro(MergeTolerance, double, 0.0, VTK_FLOAT_MAX); vtkGetMacro(MergeTolerance, double); ///@} // Used to control the relationship between the merge tolerance // (MergeTolerance) and projection tolerance (Tolerance) as these need to // be treated consistently to minimize numerical issues. The projection // tolerance addresses projection of the imprint onto the target, while // the merge tolerance is about computing accurate in-plane edge-edge // intersections. enum ToleranceStrategy { DECOUPLED_TOLERANCES = 0, LINKED_TOLERANCES = 1 }; ///@{ /** * Specify the relationship between the merge tolerance and the projection * tolerance. By default (DECOUPLED_TOLERANCES), the merge and projection * tolerance are independent of one another. Otherwise, the tolerances may * be linked (LINKED_TOLERANCES), so that the projection tolerance is * linked to (i.e., equal to) the merge tolerance. */ vtkSetClampMacro(ToleranceStrategy, int, DECOUPLED_TOLERANCES, LINKED_TOLERANCES); vtkGetMacro(ToleranceStrategy, int); void SetToleranceStrategyToDecoupled() { this->SetToleranceStrategy(DECOUPLED_TOLERANCES); } void SetToleranceStrategyToLinked() { this->SetToleranceStrategy(LINKED_TOLERANCES); } ///@} enum SpecifiedOutput { TARGET_CELLS = 0, IMPRINTED_CELLS = 1, PROJECTED_IMPRINT = 2, IMPRINTED_REGION = 3, MERGED_IMPRINT = 5 }; ///@{ /** * Control what is output by the filter. This can be useful for debugging * or to extract portions of the data. The choices are: TARGET_CELLS - * output the target cells in contact (relative to the tolerance) of the * imprint mesh; IMPRINTED_CELLS - output the target's imprinted cells * after intersection and triangulation with the imprint mesh; * PROJECTED_IMPRINT - project the imprint mesh onto the target mesh, * modifying the imprint mesh point coordinates to lie on the target * mesh; IMPRINTED_REGION - extract just the area of contact between the * target and imprint; and MERGED_IMPRINT - merge the target and imprint * mesh after the imprint operation. By default, MERGED_IMPRINT is * produced. */ vtkSetClampMacro(OutputType, int, TARGET_CELLS, MERGED_IMPRINT); vtkGetMacro(OutputType, int); void SetOutputTypeToTargetCells() { this->SetOutputType(TARGET_CELLS); } void SetOutputTypeToImprintedCells() { this->SetOutputType(IMPRINTED_CELLS); } void SetOutputTypeToProjectedImprint() { this->SetOutputType(PROJECTED_IMPRINT); } void SetOutputTypeToImprintedRegion() { this->SetOutputType(IMPRINTED_REGION); } void SetOutputTypeToMergedImprint() { this->SetOutputType(MERGED_IMPRINT); } ///@} ///@{ /** * Indicate whether to insert just the boundary edges of the imprint mesh * (i.e., do not insert the interior edges). (Boundary edges are mesh edges * used by exactly one cell.) If inserting boundary edges, the imprint * operation is similar to a cookie cutter operation. By default, boundary * edge insertion is off. */ vtkSetMacro(BoundaryEdgeInsertion, bool); vtkGetMacro(BoundaryEdgeInsertion, bool); vtkBooleanMacro(BoundaryEdgeInsertion, bool); ///@} ///@{ /** * Indicate whether cell data from the input target is to be passed through * to the output mesh. By default, PassCellData is enabled. */ vtkSetMacro(PassCellData, bool); vtkGetMacro(PassCellData, bool); vtkBooleanMacro(PassCellData, bool); ///@} ///@{ /** * Indicate whether point data from the input target mesh and the imprint * mesh are to be passed through and/or interpolated to the output mesh. By * default, PassPointData is enabled. Note: both the input mesh points and * the imprint points must have identical point data. Otherwise, a set * intersection operation will be performed to process just the point data * arrays common to both the mesh point data and imprint point data. */ vtkSetMacro(PassPointData, bool); vtkGetMacro(PassPointData, bool); vtkBooleanMacro(PassPointData, bool); ///@} enum PointInterpolationType { USE_TARGET_EDGES = 0, USE_IMPRINT_EDGES = 1 }; ///@{ /** * If PassPointData is on, indicate how new point data is to generated at * the intersection points between the input target mesh edges and the * imprint edges By default, PointInterpolation is set to USE_TARGET_EDGES. */ vtkSetClampMacro(PointInterpolation, int, USE_TARGET_EDGES, USE_IMPRINT_EDGES); vtkGetMacro(PointInterpolation, int); void SetPointInterpolationToTargetEdges() { this->SetPointInterpolation(USE_TARGET_EDGES); } void SetPointInterpolationToImprintEdges() { this->SetPointInterpolation(USE_IMPRINT_EDGES); } ///@} enum DebugOutput { NO_DEBUG_OUTPUT = 0, TRIANGULATION_INPUT = 1, TRIANGULATION_OUTPUT = 2 }; ///@{ /** * Indicate whether the output should be triangulated. By default (i.e., * TriangulateOutputOff) the imprint cells, if not triangles nor intersect * target cell boundaries, will not be triangulated. (Cells in the * transition region are always triangulated because they are frequently * concave.) */ vtkSetMacro(TriangulateOutput, bool); vtkGetMacro(TriangulateOutput, bool); vtkBooleanMacro(TriangulateOutput, bool); ///@} ///@{ /** * The following methods support debugging. By default, NO_DEBUG_OUTPUT is * produced and the second output of this filter is empty. If TRIANGULATION_INPUT * is set, then the input points and edges contained by the target DebugCellId are * output to the second output to this filter. If TRIANGULATION_OUTPUT is * set, then the output triangulation for the specified target cellId is * placed in a second output to this filter. */ vtkSetClampMacro(DebugOutputType, int, NO_DEBUG_OUTPUT, TRIANGULATION_OUTPUT); vtkGetMacro(DebugOutputType, int); void SetDebugOutputTypeToNoDebugOutput() { this->SetDebugOutputType(NO_DEBUG_OUTPUT); } void SetDebugOutputTypeToTriangulationInput() { this->SetDebugOutputType(TRIANGULATION_INPUT); } void SetDebugOutputTypeToTriangulationOutput() { this->SetDebugOutputType(TRIANGULATION_OUTPUT); } vtkSetMacro(DebugCellId, vtkIdType); vtkGetMacro(DebugCellId, vtkIdType); ///@{ ///@{ /** * Get the output data (in the second output, if the DebugOutput != * NO_DEBUG_OUTPUT). */ vtkPolyData* GetDebugOutput(); ///@} protected: vtkImprintFilter(); ~vtkImprintFilter() override; double Tolerance; double MergeTolerance; int MergeToleranceType; int ToleranceStrategy; double ComputeMergeTolerance(vtkPolyData* pdata); int OutputType; bool BoundaryEdgeInsertion; bool TriangulateOutput; bool PassCellData; bool PassPointData; int PointInterpolation; int DebugOutputType; vtkIdType DebugCellId; int RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; int RequestUpdateExtent(vtkInformation*, vtkInformationVector**, vtkInformationVector*) override; private: vtkImprintFilter(const vtkImprintFilter&) = delete; void operator=(const vtkImprintFilter&) = delete; }; VTK_ABI_NAMESPACE_END #endif