1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkAttributesErrorMetric.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 "vtkAttributesErrorMetric.h"
16 
17 #include "vtkGenericAdaptorCell.h"
18 #include "vtkGenericAttribute.h"
19 #include "vtkGenericAttributeCollection.h"
20 #include "vtkGenericDataSet.h"
21 #include "vtkObjectFactory.h"
22 #include <cassert>
23 #include <cmath>
24 
25 vtkStandardNewMacro(vtkAttributesErrorMetric);
26 
27 //------------------------------------------------------------------------------
vtkAttributesErrorMetric()28 vtkAttributesErrorMetric::vtkAttributesErrorMetric()
29 {
30   this->AttributeTolerance = 0.1;         // arbitrary
31   this->AbsoluteAttributeTolerance = 0.1; // arbitrary
32   this->SquareAbsoluteAttributeTolerance =
33     this->AbsoluteAttributeTolerance * this->AbsoluteAttributeTolerance;
34   this->Range = 0;
35   this->DefinedByAbsolute = 1;
36 }
37 
38 //------------------------------------------------------------------------------
39 vtkAttributesErrorMetric::~vtkAttributesErrorMetric() = default;
40 
41 //------------------------------------------------------------------------------
42 // Description:
43 // Set the absolute attribute accuracy to `value'. See
44 // GetAbsoluteAttributeTolerance() for details.
45 // \pre valid_range_value: value>0
SetAbsoluteAttributeTolerance(double value)46 void vtkAttributesErrorMetric::SetAbsoluteAttributeTolerance(double value)
47 {
48   assert("pre: valid_range_value" && value > 0);
49   if (this->AbsoluteAttributeTolerance != value || !this->DefinedByAbsolute)
50   {
51     this->AbsoluteAttributeTolerance = value;
52     this->SquareAbsoluteAttributeTolerance =
53       this->AbsoluteAttributeTolerance * this->AbsoluteAttributeTolerance;
54     this->Range = 0;
55     this->DefinedByAbsolute = 1;
56     this->Modified();
57   }
58 }
59 
60 //------------------------------------------------------------------------------
61 // Description:
62 // Set the relative attribute accuracy to `value'. See
63 // GetAttributeTolerance() for details.
64 // \pre valid_range_value: value>0 && value<1
SetAttributeTolerance(double value)65 void vtkAttributesErrorMetric::SetAttributeTolerance(double value)
66 {
67   assert("pre: valid_range_value" && value > 0 && value < 1);
68   if (this->AttributeTolerance != value || this->DefinedByAbsolute)
69   {
70     this->AttributeTolerance = value;
71     this->DefinedByAbsolute = 0;
72     this->Modified();
73   }
74 }
75 
76 //------------------------------------------------------------------------------
RequiresEdgeSubdivision(double * leftPoint,double * midPoint,double * rightPoint,double alpha)77 int vtkAttributesErrorMetric::RequiresEdgeSubdivision(
78   double* leftPoint, double* midPoint, double* rightPoint, double alpha)
79 {
80   assert("pre: leftPoint_exists" && leftPoint != nullptr);
81   assert("pre: midPoint_exists" && midPoint != nullptr);
82   assert("pre: rightPoint_exists" && rightPoint != nullptr);
83   assert("pre: clamped_alpha" && alpha > 0 && alpha < 1);
84 
85   int result;
86   double ae;
87   vtkGenericAttributeCollection* ac;
88 
89   this->ComputeSquareAbsoluteAttributeTolerance();
90 
91   const int ATTRIBUTE_OFFSET = 6;
92 
93   ac = this->DataSet->GetAttributes();
94   vtkGenericAttribute* a = ac->GetAttribute(ac->GetActiveAttribute());
95 
96   if (this->GenericCell->IsAttributeLinear(a))
97   {
98     // don't need to do anything:
99     ae = 0;
100   }
101   else
102   {
103     if (ac->GetActiveComponent() >= 0)
104     {
105       int i = ac->GetAttributeIndex(ac->GetActiveAttribute()) + ac->GetActiveComponent() +
106         ATTRIBUTE_OFFSET;
107       double tmp = leftPoint[i] + alpha * (rightPoint[i] - leftPoint[i]) - midPoint[i];
108       ae = tmp * tmp;
109     }
110     else // module of the vector
111     {
112       int i = ac->GetAttributeIndex(ac->GetActiveAttribute()) + ATTRIBUTE_OFFSET;
113       int j = 0;
114       int c = ac->GetNumberOfComponents();
115       double tmp;
116 #if 0
117       // If x and y are two vectors, we compute: ||x|-|y||
118       double interpolatedValueMod=0;
119       double midValueMod=0;
120       while(j<c)
121       {
122         tmp=leftPoint[i+j]+alpha*(rightPoint[i+j]-leftPoint[i+j]);
123         interpolatedValueMod+=tmp*tmp;
124         tmp=midPoint[i+j];
125         midValueMod+=tmp*tmp;
126         ++j;
127       }
128       tmp=sqrt(midValueMod)-sqrt(interpolatedValueMod);
129       ae=tmp*tmp;
130 #else
131       // If x and y are two vectors, we compute: |x-y|
132       // We should compute ||x|-|y|| but |x-y| is usually enough
133       // and tends to produce less degenerated edges.
134       // Remind that: ||x|-|y||<=|x-y|
135       ae = 0;
136       while (j < c)
137       {
138         tmp = leftPoint[i + j] + alpha * (rightPoint[i + j] - leftPoint[i + j]) - midPoint[i + j];
139         ae += tmp * tmp;
140         ++j;
141       }
142 #endif
143     }
144     assert("check: positive_ae" && ae >= 0);
145   }
146 
147   if (this->SquareAbsoluteAttributeTolerance == 0)
148   {
149     result = fabs(ae) > 0.0001;
150   }
151   else
152   {
153     result = ae > this->SquareAbsoluteAttributeTolerance;
154   }
155   return result;
156 }
157 
158 //------------------------------------------------------------------------------
159 // Description:
160 // Return the error at the mid-point. The type of error depends on the state
161 // of the concrete error metric. For instance, it can return an absolute
162 // or relative error metric.
163 // See RequiresEdgeSubdivision() for a description of the arguments.
164 // \post positive_result: result>=0
GetError(double * leftPoint,double * midPoint,double * rightPoint,double alpha)165 double vtkAttributesErrorMetric::GetError(
166   double* leftPoint, double* midPoint, double* rightPoint, double alpha)
167 {
168   assert("pre: leftPoint_exists" && leftPoint != nullptr);
169   assert("pre: midPoint_exists" && midPoint != nullptr);
170   assert("pre: rightPoint_exists" && rightPoint != nullptr);
171   assert("pre: clamped_alpha" && alpha > 0 && alpha < 1);
172 
173   double ae;
174   vtkGenericAttributeCollection* ac;
175 
176   this->ComputeSquareAbsoluteAttributeTolerance();
177 
178   const int ATTRIBUTE_OFFSET = 6;
179 
180   ac = this->DataSet->GetAttributes();
181   vtkGenericAttribute* a = ac->GetAttribute(ac->GetActiveAttribute());
182 
183   if (this->GenericCell->IsAttributeLinear(a))
184   {
185     // don't need to do anything:
186     ae = 0;
187   }
188   else
189   {
190     if (ac->GetActiveComponent() >= 0) // one component
191     {
192       int i = ac->GetAttributeIndex(ac->GetActiveAttribute()) + ac->GetActiveComponent() +
193         ATTRIBUTE_OFFSET;
194       double tmp = leftPoint[i] + alpha * (rightPoint[i] - leftPoint[i]) - midPoint[i];
195       ae = tmp * tmp;
196     }
197     else // module of the vector
198     {
199       // If x and y are two vectors, we compute: |x-y|
200       // We should compute ||x|-|y|| but |x-y| is usually enough
201       // and tends to produce less degenerated edges.
202       // Remind that: ||x|-|y||<=|x-y|
203       int i = ac->GetAttributeIndex(ac->GetActiveAttribute()) + ATTRIBUTE_OFFSET;
204       int j = 0;
205       int c = ac->GetNumberOfComponents();
206       double tmp;
207 
208       ae = 0;
209       while (j < c)
210       {
211         tmp = leftPoint[i + j] + alpha * (rightPoint[i + j] - leftPoint[i + j]) - midPoint[i + j];
212         ae += tmp * tmp;
213         ++j;
214       }
215     }
216   }
217 
218   double result;
219 
220   if (this->Range != 0)
221   {
222     result = sqrt(ae) / this->Range;
223   }
224   else
225   {
226     result = 0;
227   }
228 
229   assert("post: positive_result" && result >= 0);
230 
231   return result;
232 }
233 
234 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)235 void vtkAttributesErrorMetric::PrintSelf(ostream& os, vtkIndent indent)
236 {
237   this->Superclass::PrintSelf(os, indent);
238   os << indent << "AttributeTolerance: " << this->AttributeTolerance << endl;
239   os << indent << "AbsoluteAttributeTolerance: " << this->AbsoluteAttributeTolerance << endl;
240 }
241 
242 //------------------------------------------------------------------------------
243 // Description:
244 // Compute the absolute attribute tolerance, only if the cached value is
245 // obsolete.
ComputeSquareAbsoluteAttributeTolerance()246 void vtkAttributesErrorMetric::ComputeSquareAbsoluteAttributeTolerance()
247 {
248   if (!this->DefinedByAbsolute)
249   {
250     if (this->GetMTime() > this->SquareAbsoluteAttributeToleranceComputeTime)
251     {
252       vtkGenericAttributeCollection* ac = this->DataSet->GetAttributes();
253       vtkGenericAttribute* a = ac->GetAttribute(ac->GetActiveAttribute());
254 
255       int i = ac->GetActiveComponent();
256 
257       double r[2];
258 
259       a->GetRange(i, r);
260 
261       double tmp = (r[1] - r[0]) * this->AttributeTolerance;
262 
263       this->Range = r[1] - r[0];
264 
265       this->SquareAbsoluteAttributeTolerance = tmp * tmp;
266       this->SquareAbsoluteAttributeToleranceComputeTime.Modified();
267       this->AbsoluteAttributeTolerance = sqrt(this->SquareAbsoluteAttributeTolerance);
268     }
269   }
270 }
271