1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkGenericCellTessellator.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 #include "vtkGenericCellTessellator.h"
16 #include "vtkObjectFactory.h"
17 
18 #include "vtkCellArray.h"
19 #include "vtkCollection.h"
20 #include "vtkDoubleArray.h"
21 #include "vtkGenericAdaptorCell.h"
22 #include "vtkGenericAttribute.h"
23 #include "vtkGenericAttributeCollection.h"
24 #include "vtkGenericCellIterator.h"
25 #include "vtkGenericSubdivisionErrorMetric.h"
26 #include "vtkIdList.h"
27 #include "vtkMergePoints.h"
28 #include "vtkPointData.h"
29 #include "vtkPoints.h"
30 
31 #include <cassert>
32 
33 #include "vtkMath.h"
34 
35 vtkCxxSetObjectMacro(vtkGenericCellTessellator, ErrorMetrics, vtkCollection);
36 
37 //------------------------------------------------------------------------------
38 // Create the tessellator helper with a default of 0.25 for threshold
vtkGenericCellTessellator()39 vtkGenericCellTessellator::vtkGenericCellTessellator()
40 {
41   this->DataSet = nullptr;
42   this->ErrorMetrics = vtkCollection::New();
43   this->MaxErrorsCapacity = 0;
44   this->MaxErrors = nullptr;
45   this->Measurement = 0;
46 }
47 
48 //------------------------------------------------------------------------------
~vtkGenericCellTessellator()49 vtkGenericCellTessellator::~vtkGenericCellTessellator()
50 {
51   this->SetErrorMetrics(nullptr);
52   delete[] this->MaxErrors;
53 }
54 
55 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)56 void vtkGenericCellTessellator::PrintSelf(ostream& os, vtkIndent indent)
57 {
58   this->Superclass::PrintSelf(os, indent);
59 
60   os << indent << "Measurement: " << this->Measurement << endl;
61   os << indent << "ErrorMetrics: " << this->ErrorMetrics << endl;
62   /* this->MaxErrorsCapacity */
63   /* this->MaxErrors */
64 }
65 
66 //------------------------------------------------------------------------------
67 // Description:
68 // Does the edge need to be subdivided according to at least one error
69 // metric? The edge is defined by its `leftPoint' and its `rightPoint'.
70 // `leftPoint', `midPoint' and `rightPoint' have to be initialized before
71 // calling RequiresEdgeSubdivision().
72 // Their format is global coordinates, parametric coordinates and
73 // point centered attributes: xyx rst abc de...
74 // `alpha' is the normalized abscissa of the midpoint along the edge.
75 // (close to 0 means close to the left point, close to 1 means close to the
76 // right point)
77 // \pre leftPoint_exists: leftPoint!=0
78 // \pre midPoint_exists: midPoint!=0
79 // \pre rightPoint_exists: rightPoint!=0
80 // \pre clamped_alpha: alpha>0 && alpha<1
81 // \pre valid_size: sizeof(leftPoint)=sizeof(midPoint)=sizeof(rightPoint)
82 //          =GetAttributeCollection()->GetNumberOfPointCenteredComponents()+6
RequiresEdgeSubdivision(double * leftPoint,double * midPoint,double * rightPoint,double alpha)83 int vtkGenericCellTessellator::RequiresEdgeSubdivision(
84   double* leftPoint, double* midPoint, double* rightPoint, double alpha)
85 {
86   assert("pre: leftPoint_exists" && leftPoint != nullptr);
87   assert("pre: midPoint_exists" && midPoint != nullptr);
88   assert("pre: rightPoint_exists" && rightPoint != nullptr);
89   assert("pre: clamped_alpha" && alpha > 0 && alpha < 1);
90 
91   int result = 0;
92   this->ErrorMetrics->InitTraversal();
93   vtkGenericSubdivisionErrorMetric* e =
94     static_cast<vtkGenericSubdivisionErrorMetric*>(this->ErrorMetrics->GetNextItemAsObject());
95 
96   // Once we found at least one error metric that need subdivision,
97   // the subdivision has to be done and there is no need to check for other
98   // error metrics.
99   while (!result && e != nullptr)
100   {
101     result = e->RequiresEdgeSubdivision(leftPoint, midPoint, rightPoint, alpha);
102     e = static_cast<vtkGenericSubdivisionErrorMetric*>(this->ErrorMetrics->GetNextItemAsObject());
103   }
104 
105   return result;
106 }
107 
108 //------------------------------------------------------------------------------
109 // Description:
110 // Update the max error of each error metric according to the error at the
111 // mid-point. The type of error depends on the state
112 // of the concrete error metric. For instance, it can return an absolute
113 // or relative error metric.
114 // See RequiresEdgeSubdivision() for a description of the arguments.
115 // \pre leftPoint_exists: leftPoint!=0
116 // \pre midPoint_exists: midPoint!=0
117 // \pre rightPoint_exists: rightPoint!=0
118 // \pre clamped_alpha: alpha>0 && alpha<1
119 // \pre valid_size: sizeof(leftPoint)=sizeof(midPoint)=sizeof(rightPoint)
120 //          =GetAttributeCollection()->GetNumberOfPointCenteredComponents()+6
UpdateMaxError(double * leftPoint,double * midPoint,double * rightPoint,double alpha)121 void vtkGenericCellTessellator::UpdateMaxError(
122   double* leftPoint, double* midPoint, double* rightPoint, double alpha)
123 {
124   assert("pre: leftPoint_exists" && leftPoint != nullptr);
125   assert("pre: midPoint_exists" && midPoint != nullptr);
126   assert("pre: rightPoint_exists" && rightPoint != nullptr);
127   assert("pre: clamped_alpha" && alpha > 0 && alpha < 1);
128 
129   this->ErrorMetrics->InitTraversal();
130   vtkGenericSubdivisionErrorMetric* e =
131     static_cast<vtkGenericSubdivisionErrorMetric*>(this->ErrorMetrics->GetNextItemAsObject());
132 
133   // Once we found at least one error metric that need subdivision,
134   // the subdivision has to be done and there is no need to check for other
135   // error metrics.
136   for (int i = 0; e != nullptr; ++i)
137   {
138     double error = e->GetError(leftPoint, midPoint, rightPoint, alpha);
139     assert("check: positive_error" && error >= 0);
140     if (error > this->MaxErrors[i])
141     {
142       this->MaxErrors[i] = error;
143     }
144     e = static_cast<vtkGenericSubdivisionErrorMetric*>(this->ErrorMetrics->GetNextItemAsObject());
145   }
146 }
147 
148 //------------------------------------------------------------------------------
149 // Description:
150 // Init the error metric with the dataset. Should be called in each filter
151 // before any tessellation of any cell.
InitErrorMetrics(vtkGenericDataSet * ds)152 void vtkGenericCellTessellator::InitErrorMetrics(vtkGenericDataSet* ds)
153 {
154   this->Initialize(ds);
155   this->ErrorMetrics->InitTraversal();
156   vtkGenericSubdivisionErrorMetric* e =
157     static_cast<vtkGenericSubdivisionErrorMetric*>(this->ErrorMetrics->GetNextItemAsObject());
158 
159   while (e != nullptr)
160   {
161     e->SetDataSet(ds);
162     e = static_cast<vtkGenericSubdivisionErrorMetric*>(this->ErrorMetrics->GetNextItemAsObject());
163   }
164 
165   if (this->Measurement)
166   {
167     this->ResetMaxErrors();
168   }
169 }
170 
171 //------------------------------------------------------------------------------
172 // Description:
173 // Reset the maximal error of each error metric. The purpose of the maximal
174 // error is to measure the quality of a fixed subdivision.
ResetMaxErrors()175 void vtkGenericCellTessellator::ResetMaxErrors()
176 {
177   int c = this->ErrorMetrics->GetNumberOfItems();
178 
179   // Allocate the array.
180   if (c > this->MaxErrorsCapacity)
181   {
182     this->MaxErrorsCapacity = c;
183     delete[] this->MaxErrors;
184     this->MaxErrors = new double[this->MaxErrorsCapacity];
185   }
186 
187   for (int i = 0; i < c; ++i)
188   {
189     this->MaxErrors[i] = 0;
190   }
191 }
192 
193 //------------------------------------------------------------------------------
194 // Description:
195 // Get the maximum error measured after the fixed subdivision.
196 // \pre errors_exists: errors!=0
197 // \pre valid_size: sizeof(errors)==GetErrorMetrics()->GetNumberOfItems()
GetMaxErrors(double * errors)198 void vtkGenericCellTessellator::GetMaxErrors(double* errors)
199 {
200   assert("pre: errors_exists" && errors != nullptr);
201 
202   int c = this->ErrorMetrics->GetNumberOfItems();
203   for (int i = 0; i < c; ++i)
204   {
205     errors[i] = this->MaxErrors[i];
206   }
207 }
208 
209 //------------------------------------------------------------------------------
210 // Description:
211 // Send the current cell to error metrics. Should be called at the beginning
212 // of the implementation of Tessellate(), Triangulate()
213 // or TessellateFace()
214 // \pre cell_exists: cell!=0
SetGenericCell(vtkGenericAdaptorCell * cell)215 void vtkGenericCellTessellator::SetGenericCell(vtkGenericAdaptorCell* cell)
216 {
217   assert("pre: cell_exists" && cell != nullptr);
218 
219   this->ErrorMetrics->InitTraversal();
220   vtkGenericSubdivisionErrorMetric* e =
221     static_cast<vtkGenericSubdivisionErrorMetric*>(this->ErrorMetrics->GetNextItemAsObject());
222 
223   while (e != nullptr)
224   {
225     e->SetGenericCell(cell);
226     e = static_cast<vtkGenericSubdivisionErrorMetric*>(this->ErrorMetrics->GetNextItemAsObject());
227   }
228 }
229