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 "vtkObjectFactory.h"
18 #include "vtkGenericAttribute.h"
19 #include "vtkGenericAttributeCollection.h"
20 #include "vtkGenericAdaptorCell.h"
21 #include "vtkGenericDataSet.h"
22 #include <cassert>
23 
24 vtkStandardNewMacro(vtkAttributesErrorMetric);
25 
26 //-----------------------------------------------------------------------------
vtkAttributesErrorMetric()27 vtkAttributesErrorMetric::vtkAttributesErrorMetric()
28 {
29   this->AttributeTolerance = 0.1; // arbitrary
30   this->AbsoluteAttributeTolerance = 0.1; // arbitrary
31   this->SquareAbsoluteAttributeTolerance=this->AbsoluteAttributeTolerance*this->AbsoluteAttributeTolerance;
32   this->Range=0;
33   this->DefinedByAbsolute=1;
34 }
35 
36 //-----------------------------------------------------------------------------
37 vtkAttributesErrorMetric::~vtkAttributesErrorMetric() = default;
38 
39 //-----------------------------------------------------------------------------
40 // Description:
41 // Set the absolute attribute accuracy to `value'. See
42 // GetAbsoluteAttributeTolerance() for details.
43 // \pre valid_range_value: value>0
SetAbsoluteAttributeTolerance(double value)44 void vtkAttributesErrorMetric::SetAbsoluteAttributeTolerance(double value)
45 {
46   assert("pre: valid_range_value" && value>0);
47   if(this->AbsoluteAttributeTolerance!=value || !this->DefinedByAbsolute)
48   {
49     this->AbsoluteAttributeTolerance=value;
50     this->SquareAbsoluteAttributeTolerance=this->AbsoluteAttributeTolerance*this->AbsoluteAttributeTolerance;
51     this->Range=0;
52     this->DefinedByAbsolute=1;
53     this->Modified();
54   }
55 }
56 
57 //-----------------------------------------------------------------------------
58 // Description:
59 // Set the relative attribute accuracy to `value'. See
60 // GetAttributeTolerance() for details.
61 // \pre valid_range_value: value>0 && value<1
SetAttributeTolerance(double value)62 void vtkAttributesErrorMetric::SetAttributeTolerance(double value)
63 {
64   assert("pre: valid_range_value" && value>0 && value<1);
65   if(this->AttributeTolerance!=value || this->DefinedByAbsolute)
66   {
67     this->AttributeTolerance=value;
68     this->DefinedByAbsolute=0;
69     this->Modified();
70   }
71 }
72 
73 //-----------------------------------------------------------------------------
RequiresEdgeSubdivision(double * leftPoint,double * midPoint,double * rightPoint,double alpha)74 int vtkAttributesErrorMetric::RequiresEdgeSubdivision(double *leftPoint,
75                                                       double *midPoint,
76                                                       double *rightPoint,
77                                                       double alpha)
78 {
79   assert("pre: leftPoint_exists" && leftPoint!=nullptr);
80   assert("pre: midPoint_exists" && midPoint!=nullptr);
81   assert("pre: rightPoint_exists" && rightPoint!=nullptr);
82   assert("pre: clamped_alpha" && alpha>0 && alpha<1);
83 
84   int result;
85   double ae;
86   vtkGenericAttributeCollection *ac;
87 
88   this->ComputeSquareAbsoluteAttributeTolerance();
89 
90   const int ATTRIBUTE_OFFSET=6;
91 
92   ac=this->DataSet->GetAttributes();
93   vtkGenericAttribute *a=ac->GetAttribute(ac->GetActiveAttribute());
94 
95   if(this->GenericCell->IsAttributeLinear(a))
96   {
97     //don't need to do anything:
98     ae=0;
99   }
100   else
101   {
102     if(ac->GetActiveComponent()>=0)
103     {
104       int i=ac->GetAttributeIndex(ac->GetActiveAttribute())+ac->GetActiveComponent()+ATTRIBUTE_OFFSET;
105       double tmp=leftPoint[i]+alpha*(rightPoint[i]-leftPoint[i])-midPoint[i];
106       ae=tmp*tmp;
107     }
108     else // module of the vector
109     {
110       int i=ac->GetAttributeIndex(ac->GetActiveAttribute())+ATTRIBUTE_OFFSET;
111       int j=0;
112       int c=ac->GetNumberOfComponents();
113       double tmp;
114 #if 0
115       // If x and y are two vectors, we compute: ||x|-|y||
116       double interpolatedValueMod=0;
117       double midValueMod=0;
118       while(j<c)
119       {
120         tmp=leftPoint[i+j]+alpha*(rightPoint[i+j]-leftPoint[i+j]);
121         interpolatedValueMod+=tmp*tmp;
122         tmp=midPoint[i+j];
123         midValueMod+=tmp*tmp;
124         ++j;
125       }
126       tmp=sqrt(midValueMod)-sqrt(interpolatedValueMod);
127       ae=tmp*tmp;
128 #else
129       // If x and y are two vectors, we compute: |x-y|
130       // We should compute ||x|-|y|| but |x-y| is usually enough
131       // and tends to produce less degenerated edges.
132       // Remind that: ||x|-|y||<=|x-y|
133       ae=0;
134       while(j<c)
135       {
136         tmp=leftPoint[i+j]+alpha*(rightPoint[i+j]-leftPoint[i+j])-midPoint[i+j];
137         ae+=tmp*tmp;
138         ++j;
139       }
140 #endif
141     }
142     assert("check: positive_ae" && ae>=0);
143   }
144 
145   if(this->SquareAbsoluteAttributeTolerance==0)
146   {
147     result=fabs(ae)>0.0001;
148   }
149   else
150   {
151     result=ae>this->SquareAbsoluteAttributeTolerance;
152   }
153   return result;
154 }
155 
156 //-----------------------------------------------------------------------------
157 // Description:
158 // Return the error at the mid-point. The type of error depends on the state
159 // of the concrete error metric. For instance, it can return an absolute
160 // or relative error metric.
161 // See RequiresEdgeSubdivision() for a description of the arguments.
162 // \post positive_result: result>=0
GetError(double * leftPoint,double * midPoint,double * rightPoint,double alpha)163 double vtkAttributesErrorMetric::GetError(double *leftPoint,
164                                           double *midPoint,
165                                           double *rightPoint,
166                                           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 
184   if(this->GenericCell->IsAttributeLinear(a))
185   {
186     //don't need to do anything:
187     ae=0;
188   }
189   else
190   {
191     if(ac->GetActiveComponent()>=0) // one component
192     {
193       int i=ac->GetAttributeIndex(ac->GetActiveAttribute())+ac->GetActiveComponent()+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