1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkQuadraticQuad.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 "vtkQuadraticQuad.h"
16 
17 #include "vtkObjectFactory.h"
18 #include "vtkCellData.h"
19 #include "vtkDoubleArray.h"
20 #include "vtkMath.h"
21 #include "vtkPointData.h"
22 #include "vtkQuad.h"
23 #include "vtkQuadraticEdge.h"
24 #include "vtkPoints.h"
25 
26 vtkStandardNewMacro(vtkQuadraticQuad);
27 
28 //----------------------------------------------------------------------------
29 // Construct the quad with eight points.
vtkQuadraticQuad()30 vtkQuadraticQuad::vtkQuadraticQuad()
31 {
32   this->Edge = vtkQuadraticEdge::New();
33   this->Quad = vtkQuad::New();
34   this->PointData = vtkPointData::New();
35   this->CellData = vtkCellData::New();
36   this->CellScalars = vtkDoubleArray::New();
37   this->CellScalars->SetNumberOfTuples(9);
38   this->Scalars = vtkDoubleArray::New();
39   this->Scalars->SetNumberOfTuples(4);
40 
41   // We add a fictitious ninth point in order to process the cell. The ninth
42   // point is in the center of the cell.
43   this->Points->SetNumberOfPoints(9);
44   this->PointIds->SetNumberOfIds(9);
45   for (int i = 0; i < 9; i++)
46   {
47     this->Points->SetPoint(i, 0.0, 0.0, 0.0);
48     this->PointIds->SetId(i,0);
49   }
50   this->Points->SetNumberOfPoints(8);
51   this->PointIds->SetNumberOfIds(8);
52 }
53 
54 //----------------------------------------------------------------------------
~vtkQuadraticQuad()55 vtkQuadraticQuad::~vtkQuadraticQuad()
56 {
57   this->Edge->Delete();
58   this->Quad->Delete();
59 
60   this->Scalars->Delete();
61   this->PointData->Delete();
62   this->CellData->Delete();
63   this->CellScalars->Delete();
64 }
65 //----------------------------------------------------------------------------
GetEdge(int edgeId)66 vtkCell *vtkQuadraticQuad::GetEdge(int edgeId)
67 {
68   edgeId = (edgeId < 0 ? 0 : (edgeId > 3 ? 3 : edgeId ));
69   int p = (edgeId+1) % 4;
70 
71   // load point id's
72   this->Edge->PointIds->SetId(0,this->PointIds->GetId(edgeId));
73   this->Edge->PointIds->SetId(1,this->PointIds->GetId(p));
74   this->Edge->PointIds->SetId(2,this->PointIds->GetId(edgeId+4));
75 
76   // load coordinates
77   this->Edge->Points->SetPoint(0,this->Points->GetPoint(edgeId));
78   this->Edge->Points->SetPoint(1,this->Points->GetPoint(p));
79   this->Edge->Points->SetPoint(2,this->Points->GetPoint(edgeId+4));
80 
81   return this->Edge;
82 }
83 
84 //----------------------------------------------------------------------------
85 
86 static int LinearQuads[4][4] = { {0, 4, 8, 7}, {4, 1, 5, 8},
87                                  {8, 5, 2, 6}, {7, 8, 6, 3} };
88 
Subdivide(double * weights)89 void vtkQuadraticQuad::Subdivide(double *weights)
90 {
91   int i, j;
92   double pc[3], x[3];
93 
94   pc[0] = pc[1] = 0.5;
95   this->InterpolationFunctions(pc, weights);
96 
97   double p[3];
98   x[0] = x[1] = x[2] = 0.0;
99   for (i=0; i<8; i++)
100   {
101     this->Points->GetPoint(i, p);
102     for (j=0; j<3; j++)
103     {
104       x[j] += p[j] * weights[i];
105     }
106   }
107   this->Points->SetPoint(8,x);
108 }
109 
110 //----------------------------------------------------------------------------
EvaluatePosition(const double * x,double closestPoint[3],int & subId,double pcoords[3],double & minDist2,double weights[])111 int vtkQuadraticQuad::EvaluatePosition(const double* x,
112                                        double closestPoint[3],
113                                        int& subId, double pcoords[3],
114                                        double& minDist2, double weights[])
115 {
116   double pc[3], dist2;
117   int ignoreId, i, returnStatus=0, status;
118   double tempWeights[4];
119   double closest[3];
120 
121   // compute the midquad node
122   this->Subdivide(weights);
123 
124   //four linear quads are used
125   for (minDist2=VTK_DOUBLE_MAX, i=0; i < 4; i++)
126   {
127     this->Quad->Points->SetPoint(
128       0,this->Points->GetPoint(LinearQuads[i][0]));
129     this->Quad->Points->SetPoint(
130       1,this->Points->GetPoint(LinearQuads[i][1]));
131     this->Quad->Points->SetPoint(
132       2,this->Points->GetPoint(LinearQuads[i][2]));
133     this->Quad->Points->SetPoint(
134       3,this->Points->GetPoint(LinearQuads[i][3]));
135 
136     status = this->Quad->EvaluatePosition(x,closest,ignoreId,pc,dist2,
137                                           tempWeights);
138     if ( status != -1 && dist2 < minDist2 )
139     {
140       returnStatus = status;
141       minDist2 = dist2;
142       subId = i;
143       pcoords[0] = pc[0];
144       pcoords[1] = pc[1];
145     }
146   }
147 
148   // adjust parametric coordinates
149   if ( returnStatus != -1 )
150   {
151     if ( subId == 0 )
152     {
153       pcoords[0] /= 2.0;
154       pcoords[1] /= 2.0;
155     }
156     else if ( subId == 1 )
157     {
158       pcoords[0] = 0.5 + (pcoords[0]/2.0);
159       pcoords[1] /= 2.0;
160     }
161     else if ( subId == 2 )
162     {
163       pcoords[0] = 0.5 + (pcoords[0]/2.0);
164       pcoords[1] = 0.5 + (pcoords[1]/2.0);
165     }
166     else
167     {
168       pcoords[0] /= 2.0;
169       pcoords[1] = 0.5 + (pcoords[1]/2.0);
170     }
171     pcoords[2] = 0.0;
172     if(closestPoint!=nullptr)
173     {
174       // Compute both closestPoint and weights
175       this->EvaluateLocation(subId,pcoords,closestPoint,weights);
176     }
177     else
178     {
179       // Compute weigths only
180       this->InterpolationFunctions(pcoords,weights);
181     }
182   }
183 
184   return returnStatus;
185 }
186 //----------------------------------------------------------------------------
EvaluateLocation(int & vtkNotUsed (subId),const double pcoords[3],double x[3],double * weights)187 void vtkQuadraticQuad::EvaluateLocation(int& vtkNotUsed(subId),
188                                         const double pcoords[3],
189                                         double x[3], double *weights)
190 {
191   int i, j;
192   double pt[3];
193 
194   this->InterpolationFunctions(pcoords,weights);
195 
196   x[0] = x[1] = x[2] = 0.0;
197   for (i=0; i<8; i++)
198   {
199     this->Points->GetPoint(i, pt);
200     for (j=0; j<3; j++)
201     {
202       x[j] += pt[j] * weights[i];
203     }
204   }
205 }
206 
207 //----------------------------------------------------------------------------
CellBoundary(int subId,const double pcoords[3],vtkIdList * pts)208 int vtkQuadraticQuad::CellBoundary(int subId, const double pcoords[3], vtkIdList *pts)
209 {
210   return this->Quad->CellBoundary(subId, pcoords, pts);
211 }
212 
213 static double MidPoints[1][3] = { {0.5,0.5,0.0} };
214 
215 //----------------------------------------------------------------------------
InterpolateAttributes(vtkPointData * inPd,vtkCellData * inCd,vtkIdType cellId,vtkDataArray * cellScalars)216 void vtkQuadraticQuad::InterpolateAttributes(vtkPointData *inPd, vtkCellData *inCd,
217                                              vtkIdType cellId, vtkDataArray *cellScalars)
218 {
219   int numMidPts, i, j;
220   double weights[20];
221   double x[3];
222   double s;
223 
224   //Copy point and cell attribute data, first make sure it's empty:
225   this->PointData->Initialize();
226   this->CellData->Initialize();
227   // Make sure to copy ALL arrays. These field data have to be
228   // identical to the input field data. Otherwise, CopyData
229   // that occurs later may not work because the output field
230   // data was initialized (CopyAllocate) with the input field
231   // data.
232   this->PointData->CopyAllOn();
233   this->CellData->CopyAllOn();
234   this->PointData->CopyAllocate(inPd,9);
235   this->CellData->CopyAllocate(inCd,4);
236 
237   // copy the point data over into point ids 0->7
238   for (i=0; i<8; i++)
239   {
240     this->PointData->CopyData(inPd,this->PointIds->GetId(i),i);
241     this->CellScalars->SetValue( i, cellScalars->GetTuple1(i));
242   }
243   // copy the cell data over to the linear cell
244   this->CellData->CopyData(inCd,cellId,0);
245 
246   //Interpolate new values
247   double p[3];
248   this->Points->Resize(9);
249   this->CellScalars->Resize(9);
250   for ( numMidPts=0; numMidPts < 1; numMidPts++ )
251   {
252     this->InterpolationFunctions(MidPoints[numMidPts], weights);
253 
254     x[0] = x[1] = x[2] = 0.0;
255     s = 0.0;
256     for (i=0; i<8; i++)
257     {
258       this->Points->GetPoint(i, p);
259       for (j=0; j<3; j++)
260       {
261         x[j] += p[j] * weights[i];
262       }
263       s += cellScalars->GetTuple1(i) * weights[i];
264     }
265     this->Points->SetPoint(8+numMidPts,x);
266     this->CellScalars->SetValue(8+numMidPts,s);
267     this->PointData->InterpolatePoint(inPd, 8+numMidPts,
268                                       this->PointIds, weights);
269   }
270 }
271 
272 //----------------------------------------------------------------------------
Contour(double value,vtkDataArray * cellScalars,vtkIncrementalPointLocator * locator,vtkCellArray * verts,vtkCellArray * lines,vtkCellArray * polys,vtkPointData * inPd,vtkPointData * outPd,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd)273 void vtkQuadraticQuad::Contour(double value,
274                                vtkDataArray* cellScalars,
275                                vtkIncrementalPointLocator* locator,
276                                vtkCellArray *verts,
277                                vtkCellArray* lines,
278                                vtkCellArray* polys,
279                                vtkPointData* inPd,
280                                vtkPointData* outPd,
281                                vtkCellData* inCd,
282                                vtkIdType cellId,
283                                vtkCellData* outCd)
284 {
285   //interpolate point and cell data
286   this->InterpolateAttributes(inPd,inCd,cellId,cellScalars);
287 
288   //contour each linear quad separately
289   for (int i=0; i<4; i++)
290   {
291     for (int j=0; j<4; j++) //for each of the four vertices of the linear quad
292     {
293       this->Quad->Points->SetPoint(j,this->Points->GetPoint(LinearQuads[i][j]));
294       this->Quad->PointIds->SetId(j,LinearQuads[i][j]);
295       this->Scalars->SetValue(j,this->CellScalars->GetValue(LinearQuads[i][j]));
296     }
297 
298     this->Quad->Contour(value,this->Scalars,locator,verts,lines,polys,
299                         this->PointData,outPd,this->CellData,i,outCd);
300   }
301 }
302 //----------------------------------------------------------------------------
303 // Clip this quadratic quad using scalar value provided. Like contouring,
304 // except that it cuts the quad to produce other quads and triangles.
Clip(double value,vtkDataArray * cellScalars,vtkIncrementalPointLocator * locator,vtkCellArray * polys,vtkPointData * inPd,vtkPointData * outPd,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,int insideOut)305 void vtkQuadraticQuad::Clip(double value, vtkDataArray* cellScalars,
306                             vtkIncrementalPointLocator* locator, vtkCellArray* polys,
307                             vtkPointData* inPd, vtkPointData* outPd,
308                             vtkCellData* inCd, vtkIdType cellId,
309                             vtkCellData* outCd, int insideOut)
310 {
311   //interpolate point and cell data
312   this->InterpolateAttributes(inPd,inCd,cellId,cellScalars);
313 
314   //contour each linear quad separately
315   for (int i=0; i<4; i++)
316   {
317     for ( int j=0; j<4; j++) //for each of the four vertices of the linear quad
318     {
319       this->Quad->Points->SetPoint(j,this->Points->GetPoint(LinearQuads[i][j]));
320       this->Quad->PointIds->SetId(j,LinearQuads[i][j]);
321       this->Scalars->SetValue(j,this->CellScalars->GetValue(LinearQuads[i][j]));
322     }
323 
324     this->Quad->Clip(value,this->Scalars,locator,polys,this->PointData,
325                      outPd,this->CellData,i,outCd,insideOut);
326   }
327 }
328 
329 
330 //----------------------------------------------------------------------------
331 // Line-line intersection. Intersection has to occur within [0,1] parametric
332 // coordinates and with specified tolerance.
IntersectWithLine(const double * p1,const double * p2,double tol,double & t,double * x,double * pcoords,int & subId)333 int vtkQuadraticQuad::IntersectWithLine(const double* p1,
334                                         const double* p2,
335                                         double tol,
336                                         double& t,
337                                         double* x,
338                                         double* pcoords,
339                                         int& subId)
340 {
341   int subTest, i;
342   subId = 0;
343   double weights[8];
344 
345   //first define the midquad point
346   this->Subdivide(weights);
347 
348   //intersect the four linear quads
349   for (i=0; i < 4; i++)
350   {
351     this->Quad->Points->SetPoint(0,this->Points->GetPoint(LinearQuads[i][0]));
352     this->Quad->Points->SetPoint(1,this->Points->GetPoint(LinearQuads[i][1]));
353     this->Quad->Points->SetPoint(2,this->Points->GetPoint(LinearQuads[i][2]));
354     this->Quad->Points->SetPoint(3,this->Points->GetPoint(LinearQuads[i][3]));
355 
356     if (this->Quad->IntersectWithLine(p1, p2, tol, t, x, pcoords, subTest) )
357     {
358       return 1;
359     }
360   }
361 
362   return 0;
363 }
364 
365 //----------------------------------------------------------------------------
Triangulate(int vtkNotUsed (index),vtkIdList * ptIds,vtkPoints * pts)366 int vtkQuadraticQuad::Triangulate(int vtkNotUsed(index), vtkIdList *ptIds,
367                                   vtkPoints *pts)
368 {
369   pts->Reset();
370   ptIds->Reset();
371 
372   // Create six linear triangles: one at each corner and two
373   // to cover the remaining quadrilateral.
374 
375   // First the corner vertices
376   ptIds->InsertId(0,this->PointIds->GetId(0));
377   ptIds->InsertId(1,this->PointIds->GetId(4));
378   ptIds->InsertId(2,this->PointIds->GetId(7));
379   pts->InsertPoint(0,this->Points->GetPoint(0));
380   pts->InsertPoint(1,this->Points->GetPoint(4));
381   pts->InsertPoint(2,this->Points->GetPoint(7));
382 
383   ptIds->InsertId(3,this->PointIds->GetId(4));
384   ptIds->InsertId(4,this->PointIds->GetId(1));
385   ptIds->InsertId(5,this->PointIds->GetId(5));
386   pts->InsertPoint(3,this->Points->GetPoint(4));
387   pts->InsertPoint(4,this->Points->GetPoint(1));
388   pts->InsertPoint(5,this->Points->GetPoint(5));
389 
390   ptIds->InsertId(6,this->PointIds->GetId(5));
391   ptIds->InsertId(7,this->PointIds->GetId(2));
392   ptIds->InsertId(8,this->PointIds->GetId(6));
393   pts->InsertPoint(6,this->Points->GetPoint(5));
394   pts->InsertPoint(7,this->Points->GetPoint(2));
395   pts->InsertPoint(8,this->Points->GetPoint(6));
396 
397   ptIds->InsertId(9,this->PointIds->GetId(6));
398   ptIds->InsertId(10,this->PointIds->GetId(3));
399   ptIds->InsertId(11,this->PointIds->GetId(7));
400   pts->InsertPoint(9,this->Points->GetPoint(6));
401   pts->InsertPoint(10,this->Points->GetPoint(3));
402   pts->InsertPoint(11,this->Points->GetPoint(7));
403 
404   // Now the two remaining triangles
405   // Choose the triangulation that minimizes the edge length
406   // across the cell.
407   double x4[3], x5[3], x6[3], x7[3];
408   this->Points->GetPoint(4, x4);
409   this->Points->GetPoint(5, x5);
410   this->Points->GetPoint(6, x6);
411   this->Points->GetPoint(7, x7);
412 
413   if ( vtkMath::Distance2BetweenPoints(x4,x6) <=
414        vtkMath::Distance2BetweenPoints(x5,x7) )
415   {
416     ptIds->InsertId(12,this->PointIds->GetId(4));
417     ptIds->InsertId(13,this->PointIds->GetId(6));
418     ptIds->InsertId(14,this->PointIds->GetId(7));
419     pts->InsertPoint(12,this->Points->GetPoint(4));
420     pts->InsertPoint(13,this->Points->GetPoint(6));
421     pts->InsertPoint(14,this->Points->GetPoint(7));
422 
423     ptIds->InsertId(15,this->PointIds->GetId(4));
424     ptIds->InsertId(16,this->PointIds->GetId(5));
425     ptIds->InsertId(17,this->PointIds->GetId(6));
426     pts->InsertPoint(15,this->Points->GetPoint(4));
427     pts->InsertPoint(16,this->Points->GetPoint(5));
428     pts->InsertPoint(17,this->Points->GetPoint(6));
429   }
430   else
431   {
432     ptIds->InsertId(12,this->PointIds->GetId(5));
433     ptIds->InsertId(13,this->PointIds->GetId(6));
434     ptIds->InsertId(14,this->PointIds->GetId(7));
435     pts->InsertPoint(12,this->Points->GetPoint(5));
436     pts->InsertPoint(13,this->Points->GetPoint(6));
437     pts->InsertPoint(14,this->Points->GetPoint(7));
438 
439     ptIds->InsertId(15,this->PointIds->GetId(5));
440     ptIds->InsertId(16,this->PointIds->GetId(7));
441     ptIds->InsertId(17,this->PointIds->GetId(4));
442     pts->InsertPoint(15,this->Points->GetPoint(5));
443     pts->InsertPoint(16,this->Points->GetPoint(7));
444     pts->InsertPoint(17,this->Points->GetPoint(4));
445   }
446 
447   return 1;
448 }
449 
450 //----------------------------------------------------------------------------
Derivatives(int vtkNotUsed (subId),const double pcoords[3],const double * values,int dim,double * derivs)451 void vtkQuadraticQuad::Derivatives(int vtkNotUsed(subId),
452                                    const double pcoords[3], const double *values,
453                                    int dim, double *derivs)
454 {
455   double sum[3];
456   double functionDerivs[16];
457   double elemNodes[8][3];
458   double *J[3], J0[3], J1[3], J2[3];
459   double *JI[3], JI0[3], JI1[3], JI2[3];
460 
461   for(int i = 0; i<8; i++)
462   {
463     this->Points->GetPoint(i, elemNodes[i]);
464   }
465 
466   this->InterpolationDerivs(pcoords,functionDerivs);
467 
468   // Compute transposed Jacobian and inverse Jacobian
469   J[0] = J0; J[1] = J1; J[2] = J2;
470   JI[0] = JI0; JI[1] = JI1; JI[2] = JI2;
471   for(int k = 0; k<3; k++)
472   {
473     J0[k] = J1[k] = 0.0;
474   }
475 
476   for(int i = 0; i<8; i++)
477   {
478     for(int j = 0; j<2; j++)
479     {
480       for(int k = 0; k<3; k++)
481       {
482         J[j][k] += elemNodes[i][k] * functionDerivs[j*8+i];
483       }
484     }
485   }
486 
487   // Compute third row vector in transposed Jacobian and normalize it, so that Jacobian determinant stays the same.
488   vtkMath::Cross(J0,J1,J2);
489   if ( vtkMath::Normalize(J2) == 0.0 || !vtkMath::InvertMatrix(J,JI,3)) //degenerate
490   {
491     for (int j=0; j < dim; j++ )
492     {
493       for (int i=0; i < 3; i++ )
494       {
495         derivs[j*dim + i] = 0.0;
496       }
497     }
498     return;
499   }
500 
501 
502   // Loop over "dim" derivative values. For each set of values,
503   // compute derivatives
504   // in local system and then transform into modelling system.
505   // First compute derivatives in local x'-y' coordinate system
506   for (int j=0; j < dim; j++ )
507   {
508     sum[0] = sum[1] = sum[2] = 0.0;
509     for (int i=0; i < 8; i++) //loop over interp. function derivatives
510     {
511       sum[0] += functionDerivs[i] * values[dim*i + j];
512       sum[1] += functionDerivs[8 + i] * values[dim*i + j];
513     }
514 //    dBydx = sum[0]*JI[0][0] + sum[1]*JI[0][1];
515 //    dBydy = sum[0]*JI[1][0] + sum[1]*JI[1][1];
516 
517     // Transform into global system (dot product with global axes)
518     derivs[3*j] = sum[0]*JI[0][0] + sum[1]*JI[0][1];
519     derivs[3*j + 1] = sum[0]*JI[1][0] + sum[1]*JI[1][1];
520     derivs[3*j + 2] = sum[0]*JI[2][0] + sum[1]*JI[2][1];
521   }
522 }
523 
524 //----------------------------------------------------------------------------
525 // Compute interpolation functions. The first four nodes are the corner
526 // vertices; the others are mid-edge nodes.
InterpolationFunctions(const double pcoords[3],double weights[8])527 void vtkQuadraticQuad::InterpolationFunctions(const double pcoords[3],
528                                               double weights[8])
529 {
530   double r = pcoords[0];
531   double s = pcoords[1];
532 
533   //midedge weights
534   weights[4] = 4 * r * (1.0 - r) * (1.0 - s);
535   weights[5] = 4 * r             * (1.0 - s) * s;
536   weights[6] = 4 * r * (1.0 - r) *             s;
537   weights[7] = 4 *     (1.0 - r) * (1.0 - s) * s;
538 
539   //corner
540   weights[0] = (1.0 - r) * (1.0 - s) - 0.5*(weights[4]+weights[7]);
541   weights[1] = r * (1.0 - s) - 0.5*(weights[4]+weights[5]);
542   weights[2] = r * s - 0.5*(weights[5]+weights[6]);
543   weights[3] = (1.0 - r) * s - 0.5*(weights[6]+weights[7]);
544 
545 }
546 
547 //----------------------------------------------------------------------------
548 // Derivatives in parametric space.
InterpolationDerivs(const double pcoords[3],double derivs[16])549 void vtkQuadraticQuad::InterpolationDerivs(const double pcoords[3], double derivs[16])
550 {
551   // Coordinate conversion
552   double r = pcoords[0];
553   double s = pcoords[1];
554 
555   // Derivatives in the r-direction
556   // midedge
557   derivs[4] = 4 * (1.0 - s) * (1.0 - 2*r);
558   derivs[5] = 4 * (1.0 - s) * s;
559   derivs[6] = 4 * s * (1.0 - 2*r);
560   derivs[7] =-4 * (1.0 - s) * s;
561   derivs[0] =-(1.0 - s) - 0.5 * (derivs[4] + derivs[7]);
562   derivs[1] = (1.0 - s) - 0.5 * (derivs[4] + derivs[5]);
563   derivs[2] =        s  - 0.5 * (derivs[5] + derivs[6]);
564   derivs[3] =       -s  - 0.5 * (derivs[6] + derivs[7]);
565 
566   // Derivatives in the s-direction
567   // midedge
568   derivs[12] =-4 * r * (1.0 - r);
569   derivs[13] = 4 * r * (1.0 - 2*s);
570   derivs[14] = 4 * r * (1.0 - r);
571   derivs[15] = 4 * (1.0 - r) * (1.0 - 2*s);
572   derivs[8] = -(1.0 - r) - 0.5 * (derivs[12] + derivs[15]);
573   derivs[9] =       - r  - 0.5 * (derivs[12] + derivs[13]);
574   derivs[10] =        r  - 0.5 * (derivs[13] + derivs[14]);
575   derivs[11] = (1.0 - r) - 0.5 * (derivs[14] + derivs[15]);
576 }
577 
578 //----------------------------------------------------------------------------
579 static double vtkQQuadCellPCoords[24] = {0.0,0.0,0.0, 1.0,0.0,0.0,
580                                         1.0,1.0,0.0, 0.0,1.0,0.0,
581                                         0.5,0.0,0.0, 1.0,0.5,0.0,
582                                         0.5,1.0,0.0, 0.0,0.5,0.0};
GetParametricCoords()583 double *vtkQuadraticQuad::GetParametricCoords()
584 {
585   return vtkQQuadCellPCoords;
586 }
587 
588 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)589 void vtkQuadraticQuad::PrintSelf(ostream& os, vtkIndent indent)
590 {
591   this->Superclass::PrintSelf(os,indent);
592 
593   os << indent << "Edge:\n";
594   this->Edge->PrintSelf(os,indent.GetNextIndent());
595   os << indent << "Quad:\n";
596   this->Quad->PrintSelf(os,indent.GetNextIndent());
597   os << indent << "Scalars:\n";
598   this->Scalars->PrintSelf(os,indent.GetNextIndent());
599 }
600