1 /*
2  * Copyright 2003 Sandia Corporation.
3  * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
4  * license for use of this work by or on behalf of the
5  * U.S. Government. Redistribution and use in source and binary forms, with
6  * or without modification, are permitted provided that this Notice and any
7  * statement of authorship are reproduced on all copies.
8  */
9 
10 #include "vtkEdgeSubdivisionCriterion.h"
11 #include "vtkDataSetAttributes.h"
12 #include "vtkMatrix4x4.h"
13 #include "vtkStreamingTessellator.h"
14 
15 #include <cmath>
16 
PrintSelf(ostream & os,vtkIndent indent)17 void vtkEdgeSubdivisionCriterion::PrintSelf(ostream& os, vtkIndent indent)
18 {
19   this->Superclass::PrintSelf(os, indent);
20 }
21 
vtkEdgeSubdivisionCriterion()22 vtkEdgeSubdivisionCriterion::vtkEdgeSubdivisionCriterion()
23 {
24   this->FieldIds = new int[vtkStreamingTessellator::MaxFieldSize];
25   this->FieldOffsets = new int[vtkStreamingTessellator::MaxFieldSize + 1];
26   this->FieldOffsets[0] = 0;
27   this->NumberOfFields = 0;
28 }
29 
~vtkEdgeSubdivisionCriterion()30 vtkEdgeSubdivisionCriterion::~vtkEdgeSubdivisionCriterion()
31 {
32   delete[] this->FieldIds;
33   delete[] this->FieldOffsets;
34 };
35 
ResetFieldList()36 void vtkEdgeSubdivisionCriterion::ResetFieldList()
37 {
38   this->NumberOfFields = 0;
39 }
40 
PassField(int sourceId,int sourceSize,vtkStreamingTessellator * t)41 int vtkEdgeSubdivisionCriterion::PassField(int sourceId, int sourceSize, vtkStreamingTessellator* t)
42 {
43   if (sourceSize + this->FieldOffsets[this->NumberOfFields] > vtkStreamingTessellator::MaxFieldSize)
44   {
45     vtkErrorMacro(
46       "PassField source size (" << sourceSize << ") was too large for vtkStreamingTessellator");
47     return -1;
48   }
49 
50   int off = this->GetOutputField(sourceId);
51   if (off == -1)
52   {
53     this->FieldIds[this->NumberOfFields] = sourceId;
54     off = this->FieldOffsets[this->NumberOfFields];
55     t->SetFieldSize(-1, this->FieldOffsets[++this->NumberOfFields] = off + sourceSize);
56     this->Modified();
57   }
58   else
59   {
60     off = this->FieldOffsets[off];
61     vtkWarningMacro("Field " << sourceId << " is already being passed as offset " << off << ".");
62   }
63 
64   return off;
65 }
66 
DontPassField(int sourceId,vtkStreamingTessellator * t)67 bool vtkEdgeSubdivisionCriterion::DontPassField(int sourceId, vtkStreamingTessellator* t)
68 {
69   int id = this->GetOutputField(sourceId);
70   if (id == -1)
71     return false;
72 
73   int sz = this->FieldOffsets[id + 1] - this->FieldOffsets[id];
74   for (int i = id + 1; i < this->GetNumberOfFields(); ++i)
75   {
76     this->FieldIds[i - 1] = this->FieldIds[i];
77     this->FieldOffsets[i] = this->FieldOffsets[i + 1] - sz;
78   }
79   t->SetFieldSize(-1, this->FieldOffsets[this->GetNumberOfFields()]);
80   this->Modified();
81 
82   return true;
83 }
84 
GetOutputField(int sourceId) const85 int vtkEdgeSubdivisionCriterion::GetOutputField(int sourceId) const
86 {
87   for (int i = 0; i < this->NumberOfFields; ++i)
88     if (this->FieldIds[i] == sourceId)
89       return i;
90 
91   return -1;
92 }
93 
ViewDependentEval(const double * p0,double * p1,double * real_p1,const double * p2,int,vtkMatrix4x4 * Transform,const double * PixelSize,double AllowableChordError) const94 bool vtkEdgeSubdivisionCriterion::ViewDependentEval(const double* p0, double* p1, double* real_p1,
95   const double* p2, int, vtkMatrix4x4* Transform, const double* PixelSize,
96   double AllowableChordError) const
97 {
98   double real_p1t[4];
99   double intr_p1t[4];
100 
101   Transform->MultiplyPoint(real_p1, real_p1t);
102   Transform->MultiplyPoint(p1, intr_p1t);
103   double eprod = fabs(AllowableChordError * real_p1t[3] * intr_p1t[3]);
104   /*
105      fprintf( stderr, "eprod=%g, compare to <%g,%g>\n", eprod,
106      fabs(real_p1t[0]*intr_p1t[3]-intr_p1t[0]*real_p1t[3])/PixelSize[0],
107      fabs(real_p1t[1]*intr_p1t[3]-intr_p1t[1]*real_p1t[3])/PixelSize[1] );
108    */
109   if ((real_p1t[0] > real_p1t[3]) || (real_p1t[0] < -real_p1t[3]) || (real_p1t[1] > real_p1t[3]) ||
110     (real_p1t[1] < -real_p1t[3]))
111   {
112     double p0t[4];
113     double p2t[4];
114     for (int i = 0; i < 3; i++)
115     {
116       p0t[i] = p0[i];
117       p2t[i] = p2[i];
118     }
119     p0t[3] = p2t[3] = 1.;
120     Transform->MultiplyPoint(p0t, p0t);
121     Transform->MultiplyPoint(p2t, p2t);
122     int p0Code = 0, p2Code = 0;
123 #define ENDPOINT_CODE(code, pt)                                                                    \
124   if (pt[0] > pt[3])                                                                               \
125     code += 1;                                                                                     \
126   else if (pt[0] < -pt[3])                                                                         \
127     code += 2;                                                                                     \
128   if (pt[1] > pt[3])                                                                               \
129     code += 4;                                                                                     \
130   else if (pt[1] < -pt[3])                                                                         \
131     code += 8;
132 
133     ENDPOINT_CODE(p0Code, p0t);
134     ENDPOINT_CODE(p2Code, p2t);
135     if (p0Code & p2Code)
136     {
137       return false;
138     }
139   }
140   if (fabs(real_p1t[0] * intr_p1t[3] - intr_p1t[0] * real_p1t[3]) / PixelSize[0] > eprod ||
141     fabs(real_p1t[1] * intr_p1t[3] - intr_p1t[1] * real_p1t[3]) / PixelSize[1] > eprod)
142   {
143     // copy the properly interpolated point into the result
144     for (int c = 0; c < 3; ++c)
145       p1[c] = real_p1[c];
146     return true; // need to subdivide
147   }
148 
149   return false; // no need to subdivide
150 }
151 
FixedFieldErrorEval(double * p1,double * real_pf,int field_start,int criteria,double * AllowableL2Error2) const152 bool vtkEdgeSubdivisionCriterion::FixedFieldErrorEval(
153   double* p1, double* real_pf, int field_start, int criteria, double* AllowableL2Error2) const
154 {
155   int id = 0;
156   double mag;
157   while (criteria)
158   {
159     if (!(criteria & 1))
160     {
161       criteria >>= 1;
162       ++id;
163       continue;
164     }
165 
166     mag = 0.;
167     int fsz = this->FieldOffsets[id + 1] - this->FieldOffsets[id];
168     for (int c = 0; c < fsz; ++c)
169     {
170       double tmp = real_pf[c + field_start] - p1[c + field_start];
171       mag += tmp * tmp;
172     }
173     if (mag > AllowableL2Error2[id])
174     {
175       return true;
176     }
177     criteria >>= 1;
178     ++id;
179   }
180 
181   return false;
182 }
183