1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkQuad.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 "vtkQuad.h"
16 
17 #include "vtkObjectFactory.h"
18 #include "vtkCellArray.h"
19 #include "vtkCellData.h"
20 #include "vtkLine.h"
21 #include "vtkTriangle.h"
22 #include "vtkMath.h"
23 #include "vtkPlane.h"
24 #include "vtkPointData.h"
25 #include "vtkIncrementalPointLocator.h"
26 #include "vtkPoints.h"
27 
28 vtkStandardNewMacro(vtkQuad);
29 
30 static const double VTK_DIVERGED = 1.e6;
31 
32 //----------------------------------------------------------------------------
33 // Construct the quad with four points.
vtkQuad()34 vtkQuad::vtkQuad()
35 {
36   this->Points->SetNumberOfPoints(4);
37   this->PointIds->SetNumberOfIds(4);
38   for (int i = 0; i < 4; i++)
39     {
40     this->Points->SetPoint(i, 0.0, 0.0, 0.0);
41     this->PointIds->SetId(i,0);
42     }
43   this->Line = vtkLine::New();
44   this->Triangle = vtkTriangle::New();
45 }
46 
47 //----------------------------------------------------------------------------
~vtkQuad()48 vtkQuad::~vtkQuad()
49 {
50   this->Line->Delete();
51   this->Triangle->Delete();
52 }
53 
54 //----------------------------------------------------------------------------
55 static const int VTK_QUAD_MAX_ITERATION=20;
56 static const double VTK_QUAD_CONVERGED=1.e-04;
57 
ComputeNormal(vtkQuad * self,double pt1[3],double pt2[3],double pt3[3],double n[3])58 inline static void ComputeNormal(vtkQuad *self, double pt1[3], double pt2[3],
59                                  double pt3[3], double n[3])
60 {
61   vtkTriangle::ComputeNormal (pt1, pt2, pt3, n);
62 
63   // If first three points are co-linear, then use fourth point
64   //
65   double pt4[3];
66   if ( n[0] == 0.0 && n[1] == 0.0 && n[2] == 0.0 )
67     {
68     self->Points->GetPoint(3,pt4);
69     vtkTriangle::ComputeNormal (pt2, pt3, pt4, n);
70     }
71 }
72 
73 //----------------------------------------------------------------------------
EvaluatePosition(double x[3],double * closestPoint,int & subId,double pcoords[3],double & dist2,double * weights)74 int vtkQuad::EvaluatePosition(double x[3], double* closestPoint,
75                              int& subId, double pcoords[3],
76                              double& dist2, double *weights)
77 {
78   int i, j;
79   double pt1[3], pt2[3], pt3[3], pt[3], n[3];
80   double det;
81   double maxComponent;
82   int idx=0, indices[2];
83   int iteration, converged;
84   double  params[2];
85   double  fcol[2], rcol[2], scol[2], cp[3];
86   double derivs[8];
87 
88   subId = 0;
89   pcoords[0] = pcoords[1] = params[0] = params[1] = 0.5;
90 
91   // Get normal for quadrilateral
92   //
93   this->Points->GetPoint(0, pt1);
94   this->Points->GetPoint(1, pt2);
95   this->Points->GetPoint(2, pt3);
96   ComputeNormal (this, pt1, pt2, pt3, n);
97 
98   // Project point to plane
99   //
100   vtkPlane::ProjectPoint(x,pt1,n,cp);
101 
102   // Construct matrices.  Since we have over determined system, need to find
103   // which 2 out of 3 equations to use to develop equations. (Any 2 should
104   // work since we've projected point to plane.)
105   //
106   for (maxComponent=0.0, i=0; i<3; i++)
107     {
108     if (fabs(n[i]) > maxComponent)
109       {
110       maxComponent = fabs(n[i]);
111       idx = i;
112       }
113     }
114   for (j=0, i=0; i<3; i++)
115     {
116     if ( i != idx )
117       {
118       indices[j++] = i;
119       }
120     }
121 
122   // Use Newton's method to solve for parametric coordinates
123   //
124   for (iteration=converged=0; !converged
125          && (iteration < VTK_QUAD_MAX_ITERATION);
126        iteration++)
127     {
128     //  calculate element interpolation functions and derivatives
129     //
130     this->InterpolationFunctions(pcoords, weights);
131     this->InterpolationDerivs(pcoords, derivs);
132 
133     //  calculate newton functions
134     //
135     for (i=0; i<2; i++)
136       {
137       fcol[i] = rcol[i] = scol[i] = 0.0;
138       }
139     for (i=0; i<4; i++)
140       {
141       this->Points->GetPoint(i, pt);
142       for (j=0; j<2; j++)
143         {
144         fcol[j] += pt[indices[j]] * weights[i];
145         rcol[j] += pt[indices[j]] * derivs[i];
146         scol[j] += pt[indices[j]] * derivs[i+4];
147         }
148       }
149 
150     for (j=0; j<2; j++)
151       {
152       fcol[j] -= cp[indices[j]];
153       }
154 
155     //  compute determinants and generate improvements
156     //
157     if ( (det=vtkMath::Determinant2x2(rcol,scol)) == 0.0 )
158       {
159       return -1;
160       }
161 
162     pcoords[0] = params[0] - vtkMath::Determinant2x2 (fcol,scol) / det;
163     pcoords[1] = params[1] - vtkMath::Determinant2x2 (rcol,fcol) / det;
164 
165     //  check for convergence
166     //
167     if ( ((fabs(pcoords[0]-params[0])) < VTK_QUAD_CONVERGED) &&
168          ((fabs(pcoords[1]-params[1])) < VTK_QUAD_CONVERGED) )
169       {
170       converged = 1;
171       }
172     // Test for bad divergence (S.Hirschberg 11.12.2001)
173     else if ((fabs(pcoords[0]) > VTK_DIVERGED) ||
174              (fabs(pcoords[1]) > VTK_DIVERGED))
175       {
176       return -1;
177       }
178 
179     //  if not converged, repeat
180     //
181     else
182       {
183       params[0] = pcoords[0];
184       params[1] = pcoords[1];
185       }
186     }
187 
188   //  if not converged, set the parametric coordinates to arbitrary values
189   //  outside of element
190   //
191   if ( !converged )
192     {
193     return -1;
194     }
195 
196   this->InterpolationFunctions(pcoords, weights);
197 
198   if ( pcoords[0] >= -0.001 && pcoords[0] <= 1.001 &&
199        pcoords[1] >= -0.001 && pcoords[1] <= 1.001 )
200     {
201     if (closestPoint)
202       {
203       dist2 =
204         vtkMath::Distance2BetweenPoints(cp,x); //projection distance
205       closestPoint[0] = cp[0];
206       closestPoint[1] = cp[1];
207       closestPoint[2] = cp[2];
208       }
209     return 1;
210     }
211   else
212     {
213     double t;
214     double pt4[3];
215 
216     if (closestPoint)
217       {
218       this->Points->GetPoint(3, pt4);
219 
220       if ( pcoords[0] < 0.0 && pcoords[1] < 0.0 )
221         {
222         dist2 = vtkMath::Distance2BetweenPoints(x,pt1);
223         for (i=0; i<3; i++)
224           {
225         closestPoint[i] = pt1[i];
226           }
227         }
228       else if ( pcoords[0] > 1.0 && pcoords[1] < 0.0 )
229         {
230         dist2 = vtkMath::Distance2BetweenPoints(x,pt2);
231         for (i=0; i<3; i++)
232           {
233           closestPoint[i] = pt2[i];
234           }
235         }
236       else if ( pcoords[0] > 1.0 && pcoords[1] > 1.0 )
237         {
238         dist2 = vtkMath::Distance2BetweenPoints(x,pt3);
239         for (i=0; i<3; i++)
240           {
241           closestPoint[i] = pt3[i];
242           }
243         }
244       else if ( pcoords[0] < 0.0 && pcoords[1] > 1.0 )
245         {
246         dist2 = vtkMath::Distance2BetweenPoints(x,pt4);
247         for (i=0; i<3; i++)
248           {
249           closestPoint[i] = pt4[i];
250           }
251         }
252       else if ( pcoords[0] < 0.0 )
253         {
254         dist2 = vtkLine::DistanceToLine(x,pt1,pt4,t,closestPoint);
255         }
256       else if ( pcoords[0] > 1.0 )
257         {
258         dist2 = vtkLine::DistanceToLine(x,pt2,pt3,t,closestPoint);
259         }
260       else if ( pcoords[1] < 0.0 )
261         {
262         dist2 = vtkLine::DistanceToLine(x,pt1,pt2,t,closestPoint);
263         }
264       else if ( pcoords[1] > 1.0 )
265         {
266         dist2 = vtkLine::DistanceToLine(x,pt3,pt4,t,closestPoint);
267         }
268       }
269     return 0;
270     }
271 }
272 
273 //----------------------------------------------------------------------------
EvaluateLocation(int & vtkNotUsed (subId),double pcoords[3],double x[3],double * weights)274 void vtkQuad::EvaluateLocation(int& vtkNotUsed(subId), double pcoords[3],
275                                double x[3], double *weights)
276 {
277   int i, j;
278   double pt[3];
279 
280   this->InterpolationFunctions(pcoords, weights);
281 
282   x[0] = x[1] = x[2] = 0.0;
283   for (i=0; i<4; i++)
284     {
285     this->Points->GetPoint(i, pt);
286     for (j=0; j<3; j++)
287       {
288       x[j] += pt[j] * weights[i];
289       }
290     }
291 }
292 
293 //----------------------------------------------------------------------------
294 // Compute iso-parametric interpolation functions
295 //
InterpolationFunctions(double pcoords[3],double sf[4])296 void vtkQuad::InterpolationFunctions(double pcoords[3], double sf[4])
297 {
298   double rm, sm;
299 
300   rm = 1. - pcoords[0];
301   sm = 1. - pcoords[1];
302 
303   sf[0] = rm * sm;
304   sf[1] = pcoords[0] * sm;
305   sf[2] = pcoords[0] * pcoords[1];
306   sf[3] = rm * pcoords[1];
307 }
308 
309 //----------------------------------------------------------------------------
InterpolationDerivs(double pcoords[3],double derivs[8])310 void vtkQuad::InterpolationDerivs(double pcoords[3], double derivs[8])
311 {
312   double rm, sm;
313 
314   rm = 1. - pcoords[0];
315   sm = 1. - pcoords[1];
316 
317   derivs[0] = -sm;
318   derivs[1] = sm;
319   derivs[2] = pcoords[1];
320   derivs[3] = -pcoords[1];
321   derivs[4] = -rm;
322   derivs[5] = -pcoords[0];
323   derivs[6] = pcoords[0];
324   derivs[7] = rm;
325 }
326 
327 //----------------------------------------------------------------------------
CellBoundary(int vtkNotUsed (subId),double pcoords[3],vtkIdList * pts)328 int vtkQuad::CellBoundary(int vtkNotUsed(subId), double pcoords[3],
329                           vtkIdList *pts)
330 {
331   double t1=pcoords[0]-pcoords[1];
332   double t2=1.0-pcoords[0]-pcoords[1];
333 
334   pts->SetNumberOfIds(2);
335 
336   // compare against two lines in parametric space that divide element
337   // into four pieces.
338   if ( t1 >= 0.0 && t2 >= 0.0 )
339     {
340     pts->SetId(0,this->PointIds->GetId(0));
341     pts->SetId(1,this->PointIds->GetId(1));
342     }
343 
344   else if ( t1 >= 0.0 && t2 < 0.0 )
345     {
346     pts->SetId(0,this->PointIds->GetId(1));
347     pts->SetId(1,this->PointIds->GetId(2));
348     }
349 
350   else if ( t1 < 0.0 && t2 < 0.0 )
351     {
352     pts->SetId(0,this->PointIds->GetId(2));
353     pts->SetId(1,this->PointIds->GetId(3));
354     }
355 
356   else //( t1 < 0.0 && t2 >= 0.0 )
357     {
358     pts->SetId(0,this->PointIds->GetId(3));
359     pts->SetId(1,this->PointIds->GetId(0));
360     }
361 
362   if ( pcoords[0] < 0.0 || pcoords[0] > 1.0 ||
363        pcoords[1] < 0.0 || pcoords[1] > 1.0 )
364     {
365     return 0;
366     }
367   else
368     {
369     return 1;
370     }
371 }
372 
373 //----------------------------------------------------------------------------
374 // Marching (convex) quadrilaterals
375 //
376 static int edges[4][2] = { {0,1}, {1,2}, {3,2}, {0,3} };
377 
378 typedef int EDGE_LIST;
379 typedef struct {
380        EDGE_LIST edges[5];
381 } LINE_CASES;
382 
383 static LINE_CASES lineCases[] = {
384   {{-1, -1, -1, -1, -1}},
385   {{0, 3, -1, -1, -1}},
386   {{1, 0, -1, -1, -1}},
387   {{1, 3, -1, -1, -1}},
388   {{2, 1, -1, -1, -1}},
389   {{0, 3, 2, 1, -1}},
390   {{2, 0, -1, -1, -1}},
391   {{2, 3, -1, -1, -1}},
392   {{3, 2, -1, -1, -1}},
393   {{0, 2, -1, -1, -1}},
394   {{1, 0, 3, 2, -1}},
395   {{1, 2, -1, -1, -1}},
396   {{3, 1, -1, -1, -1}},
397   {{0, 1, -1, -1, -1}},
398   {{3, 0, -1, -1, -1}},
399   {{-1, -1, -1, -1, -1}}
400 };
401 
402 //----------------------------------------------------------------------------
GetEdgeArray(int edgeId)403 int *vtkQuad::GetEdgeArray(int edgeId)
404 {
405   return edges[edgeId];
406 }
407 
408 //----------------------------------------------------------------------------
Contour(double value,vtkDataArray * cellScalars,vtkIncrementalPointLocator * locator,vtkCellArray * verts,vtkCellArray * lines,vtkCellArray * vtkNotUsed (polys),vtkPointData * inPd,vtkPointData * outPd,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd)409 void vtkQuad::Contour(double value, vtkDataArray *cellScalars,
410                       vtkIncrementalPointLocator *locator,
411                       vtkCellArray *verts,
412                       vtkCellArray *lines,
413                       vtkCellArray *vtkNotUsed(polys),
414                       vtkPointData *inPd, vtkPointData *outPd,
415                       vtkCellData *inCd, vtkIdType cellId, vtkCellData *outCd)
416 {
417   static int CASE_MASK[4] = {1,2,4,8};
418   LINE_CASES *lineCase;
419   EDGE_LIST  *edge;
420   int i, j, index, *vert;
421   int newCellId;
422   vtkIdType pts[2];
423   int e1, e2;
424   double t, x1[3], x2[3], x[3], deltaScalar;
425   vtkIdType offset = verts->GetNumberOfCells();
426 
427   // Build the case table
428   for ( i=0, index = 0; i < 4; i++)
429     {
430     if (cellScalars->GetComponent(i,0) >= value)
431       {
432       index |= CASE_MASK[i];
433       }
434     }
435 
436   lineCase = lineCases + index;
437   edge = lineCase->edges;
438 
439   for ( ; edge[0] > -1; edge += 2 )
440     {
441     for (i=0; i<2; i++) // insert line
442       {
443       vert = edges[edge[i]];
444       // calculate a preferred interpolation direction
445       deltaScalar = (cellScalars->GetComponent(vert[1],0)
446                      - cellScalars->GetComponent(vert[0],0));
447       if (deltaScalar > 0)
448         {
449         e1 = vert[0]; e2 = vert[1];
450         }
451       else
452         {
453         e1 = vert[1]; e2 = vert[0];
454         deltaScalar = -deltaScalar;
455         }
456 
457       // linear interpolation
458       if (deltaScalar == 0.0)
459         {
460         t = 0.0;
461         }
462       else
463         {
464         t = (value - cellScalars->GetComponent(e1,0)) / deltaScalar;
465         }
466 
467       this->Points->GetPoint(e1, x1);
468       this->Points->GetPoint(e2, x2);
469 
470       for (j=0; j<3; j++)
471         {
472         x[j] = x1[j] + t * (x2[j] - x1[j]);
473         }
474       if ( locator->InsertUniquePoint(x, pts[i]) )
475         {
476         if ( outPd )
477           {
478           vtkIdType p1 = this->PointIds->GetId(e1);
479           vtkIdType p2 = this->PointIds->GetId(e2);
480           outPd->InterpolateEdge(inPd,pts[i],p1,p2,t);
481           }
482         }
483       }
484     // check for degenerate line
485     if ( pts[0] != pts[1] )
486       {
487       newCellId = offset + lines->InsertNextCell(2,pts);
488       outCd->CopyData(inCd,cellId,newCellId);
489       }
490     }
491 }
492 
493 //----------------------------------------------------------------------------
GetEdge(int edgeId)494 vtkCell *vtkQuad::GetEdge(int edgeId)
495 {
496   int edgeIdPlus1 = edgeId + 1;
497 
498   if (edgeIdPlus1 > 3)
499     {
500     edgeIdPlus1 = 0;
501     }
502 
503   // load point id's
504   this->Line->PointIds->SetId(0,this->PointIds->GetId(edgeId));
505   this->Line->PointIds->SetId(1,this->PointIds->GetId(edgeIdPlus1));
506 
507   // load coordinates
508   this->Line->Points->SetPoint(0,this->Points->GetPoint(edgeId));
509   this->Line->Points->SetPoint(1,this->Points->GetPoint(edgeIdPlus1));
510 
511   return this->Line;
512 }
513 
514 
515 //----------------------------------------------------------------------------
516 // Intersect plane; see whether point is in quadrilateral. This code
517 // splits the quad into two triangles and intersects them (because the
518 // quad may be non-planar).
519 //
IntersectWithLine(double p1[3],double p2[3],double tol,double & t,double x[3],double pcoords[3],int & subId)520 int vtkQuad::IntersectWithLine(double p1[3], double p2[3], double tol, double& t,
521                               double x[3], double pcoords[3], int& subId)
522 {
523   int diagonalCase;
524   double d1 = vtkMath::Distance2BetweenPoints(this->Points->GetPoint(0),
525                                              this->Points->GetPoint(2));
526   double d2 = vtkMath::Distance2BetweenPoints(this->Points->GetPoint(1),
527                                              this->Points->GetPoint(3));
528   subId = 0;
529 
530   // Figure out how to uniquely tessellate the quad. Watch out for
531   // equivalent triangulations (i.e., the triangulation is equivalent
532   // no matter where the diagonal). In this case use the point ids as
533   // a tie breaker to insure unique triangulation across the quad.
534   //
535   if ( d1 == d2 ) //rare case; discriminate based on point id
536     {
537     int i, id, maxId=0, maxIdx=0;
538     for (i=0; i<4; i++) //find the maximum id
539       {
540       if ( (id=this->PointIds->GetId(i)) > maxId )
541         {
542         maxId = id;
543         maxIdx = i;
544         }
545       }
546     if ( maxIdx == 0 || maxIdx == 2) diagonalCase = 0;
547     else diagonalCase = 1;
548     }
549   else if ( d1 < d2 )
550     {
551     diagonalCase = 0;
552     }
553   else //d2 < d1
554     {
555     diagonalCase = 1;
556     }
557 
558   // Note: in the following code the parametric coords must be adjusted to
559   // reflect the use of the triangle parametric coordinate system.
560   switch (diagonalCase)
561     {
562     case 0:
563       this->Triangle->Points->SetPoint(0,this->Points->GetPoint(0));
564       this->Triangle->Points->SetPoint(1,this->Points->GetPoint(1));
565       this->Triangle->Points->SetPoint(2,this->Points->GetPoint(2));
566       if (this->Triangle->IntersectWithLine(p1, p2, tol, t, x, pcoords, subId) )
567         {
568         pcoords[0] = pcoords[0] + pcoords[1];
569         return 1;
570         }
571       this->Triangle->Points->SetPoint(0,this->Points->GetPoint(2));
572       this->Triangle->Points->SetPoint(1,this->Points->GetPoint(3));
573       this->Triangle->Points->SetPoint(2,this->Points->GetPoint(0));
574       if (this->Triangle->IntersectWithLine(p1, p2, tol, t, x, pcoords, subId) )
575         {
576         pcoords[0] = 1.0 - (pcoords[0]+pcoords[1]);
577         pcoords[1] = 1.0 - pcoords[1];
578         return 1;
579         }
580       return 0;
581 
582     case 1:
583       this->Triangle->Points->SetPoint(0,this->Points->GetPoint(0));
584       this->Triangle->Points->SetPoint(1,this->Points->GetPoint(1));
585       this->Triangle->Points->SetPoint(2,this->Points->GetPoint(3));
586       if (this->Triangle->IntersectWithLine(p1, p2, tol, t, x, pcoords, subId) )
587         {
588         return 1;
589         }
590       this->Triangle->Points->SetPoint(0,this->Points->GetPoint(2));
591       this->Triangle->Points->SetPoint(1,this->Points->GetPoint(3));
592       this->Triangle->Points->SetPoint(2,this->Points->GetPoint(1));
593       if (this->Triangle->IntersectWithLine(p1, p2, tol, t, x, pcoords, subId) )
594         {
595         pcoords[0] = 1.0 - pcoords[0];
596         pcoords[1] = 1.0 - pcoords[1];
597         return 1;
598         }
599 
600       return 0;
601     }
602 
603   return 0;
604 }
605 
606 //----------------------------------------------------------------------------
Triangulate(int vtkNotUsed (index),vtkIdList * ptIds,vtkPoints * pts)607 int vtkQuad::Triangulate(int vtkNotUsed(index), vtkIdList *ptIds,
608                          vtkPoints *pts)
609 {
610   double d1, d2;
611 
612   pts->Reset();
613   ptIds->Reset();
614 
615   // use minimum diagonal (Delaunay triangles) - assumed convex
616   d1 = vtkMath::Distance2BetweenPoints(this->Points->GetPoint(0),
617                                    this->Points->GetPoint(2));
618   d2 = vtkMath::Distance2BetweenPoints(this->Points->GetPoint(1),
619                                    this->Points->GetPoint(3));
620 
621   if ( d1 <= d2 )
622     {
623     ptIds->InsertId(0,this->PointIds->GetId(0));
624     pts->InsertPoint(0,this->Points->GetPoint(0));
625     ptIds->InsertId(1,this->PointIds->GetId(1));
626     pts->InsertPoint(1,this->Points->GetPoint(1));
627     ptIds->InsertId(2,this->PointIds->GetId(2));
628     pts->InsertPoint(2,this->Points->GetPoint(2));
629 
630     ptIds->InsertId(3,this->PointIds->GetId(0));
631     pts->InsertPoint(3,this->Points->GetPoint(0));
632     ptIds->InsertId(4,this->PointIds->GetId(2));
633     pts->InsertPoint(4,this->Points->GetPoint(2));
634     ptIds->InsertId(5,this->PointIds->GetId(3));
635     pts->InsertPoint(5,this->Points->GetPoint(3));
636     }
637   else
638     {
639     ptIds->InsertId(0,this->PointIds->GetId(0));
640     pts->InsertPoint(0,this->Points->GetPoint(0));
641     ptIds->InsertId(1,this->PointIds->GetId(1));
642     pts->InsertPoint(1,this->Points->GetPoint(1));
643     ptIds->InsertId(2,this->PointIds->GetId(3));
644     pts->InsertPoint(2,this->Points->GetPoint(3));
645 
646     ptIds->InsertId(3,this->PointIds->GetId(1));
647     pts->InsertPoint(3,this->Points->GetPoint(1));
648     ptIds->InsertId(4,this->PointIds->GetId(2));
649     pts->InsertPoint(4,this->Points->GetPoint(2));
650     ptIds->InsertId(5,this->PointIds->GetId(3));
651     pts->InsertPoint(5,this->Points->GetPoint(3));
652     }
653 
654   return 1;
655 }
656 
657 //----------------------------------------------------------------------------
Derivatives(int vtkNotUsed (subId),double pcoords[3],double * values,int dim,double * derivs)658 void vtkQuad::Derivatives(int vtkNotUsed(subId), double pcoords[3],
659                           double *values, int dim, double *derivs)
660 {
661   double v0[2], v1[2], v2[2], v3[2], v10[3], v20[3], lenX;
662   double x0[3], x1[3], x2[3], x3[3], n[3], vec20[3], vec30[3];
663   double *J[2], J0[2], J1[2];
664   double *JI[2], JI0[2], JI1[2];
665   double funcDerivs[8], sum[2], dBydx, dBydy;
666   int i, j;
667 
668   // Project points of quad into 2D system
669   this->Points->GetPoint(0, x0);
670   this->Points->GetPoint(1, x1);
671   this->Points->GetPoint(2, x2);
672   ComputeNormal (this,x0, x1, x2, n);
673   this->Points->GetPoint(3, x3);
674 
675   for (i=0; i < 3; i++)
676     {
677     v10[i] = x1[i] - x0[i];
678     vec20[i] = x2[i] - x0[i];
679     vec30[i] = x3[i] - x0[i];
680     }
681 
682   vtkMath::Cross(n,v10,v20); //creates local y' axis
683 
684   if ( (lenX=vtkMath::Normalize(v10)) <= 0.0
685        || vtkMath::Normalize(v20) <= 0.0 ) //degenerate
686     {
687     for ( j=0; j < dim; j++ )
688       {
689       for ( i=0; i < 3; i++ )
690         {
691         derivs[j*dim + i] = 0.0;
692         }
693       }
694     return;
695     }
696 
697   v0[0] = v0[1] = 0.0; //convert points to 2D (i.e., local system)
698   v1[0] = lenX; v1[1] = 0.0;
699   v2[0] = vtkMath::Dot(vec20,v10);
700   v2[1] = vtkMath::Dot(vec20,v20);
701   v3[0] = vtkMath::Dot(vec30,v10);
702   v3[1] = vtkMath::Dot(vec30,v20);
703 
704   this->InterpolationDerivs(pcoords, funcDerivs);
705 
706   // Compute Jacobian and inverse Jacobian
707   J[0] = J0; J[1] = J1;
708   JI[0] = JI0; JI[1] = JI1;
709 
710   J[0][0] = v0[0]*funcDerivs[0] + v1[0]*funcDerivs[1] +
711             v2[0]*funcDerivs[2] + v3[0]*funcDerivs[3];
712   J[0][1] = v0[1]*funcDerivs[0] + v1[1]*funcDerivs[1] +
713             v2[1]*funcDerivs[2] + v3[1]*funcDerivs[3];
714   J[1][0] = v0[0]*funcDerivs[4] + v1[0]*funcDerivs[5] +
715             v2[0]*funcDerivs[6] + v3[0]*funcDerivs[7];
716   J[1][1] = v0[1]*funcDerivs[4] + v1[1]*funcDerivs[5] +
717             v2[1]*funcDerivs[6] + v3[1]*funcDerivs[7];
718 
719   // Compute inverse Jacobian, return if Jacobian is singular
720   if (!vtkMath::InvertMatrix(J,JI,2))
721     {
722     for ( j=0; j < dim; j++ )
723       {
724       for ( i=0; i < 3; i++ )
725         {
726         derivs[j*dim + i] = 0.0;
727         }
728       }
729     return;
730     }
731 
732   // Loop over "dim" derivative values. For each set of values,
733   // compute derivatives
734   // in local system and then transform into modelling system.
735   // First compute derivatives in local x'-y' coordinate system
736   for ( j=0; j < dim; j++ )
737     {
738     sum[0] = sum[1] = 0.0;
739     for ( i=0; i < 4; i++) //loop over interp. function derivatives
740       {
741       sum[0] += funcDerivs[i] * values[dim*i + j];
742       sum[1] += funcDerivs[4 + i] * values[dim*i + j];
743       }
744     dBydx = sum[0]*JI[0][0] + sum[1]*JI[0][1];
745     dBydy = sum[0]*JI[1][0] + sum[1]*JI[1][1];
746 
747     // Transform into global system (dot product with global axes)
748     derivs[3*j] = dBydx * v10[0] + dBydy * v20[0];
749     derivs[3*j + 1] = dBydx * v10[1] + dBydy * v20[1];
750     derivs[3*j + 2] = dBydx * v10[2] + dBydy * v20[2];
751     }
752 }
753 
754 //----------------------------------------------------------------------------
755 // support quad clipping
756 typedef int QUAD_EDGE_LIST;
757 typedef struct {
758        QUAD_EDGE_LIST edges[14];
759 } QUAD_CASES;
760 
761 static QUAD_CASES quadCases[] = {
762 {{  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 0
763 {{   3, 100,   0,   3,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 1
764 {{   3, 101,   1,   0,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 2
765 {{   4, 100, 101,   1,   3,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 3
766 {{   3, 102,   2,   1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 4
767 {{   3, 100,   0,   3,   3, 102,   2,   1,   4,   0,   1,   2,   3,  -1}}, // 5
768 {{   4, 101, 102,   2,   0,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 6
769 {{   3, 100, 101,   3,   3, 101,   2,   3,   3, 101, 102,   2,  -1,  -1}}, // 7
770 {{   3, 103,   3,   2,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 8
771 {{   4, 100,   0,   2, 103,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 9
772 {{   3, 101,   1,   0,   3, 103,   3,   2,   4,   0,   1,   2,   3,  -1}}, // 10
773 {{   3, 100, 101,   1,   3, 100,   1,   2,   3, 100,   2, 103,  -1,  -1}}, // 11
774 {{   4, 102, 103,   3,   1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 12
775 {{   3, 100,   0, 103,   3,   0,   1, 103,   3,   1, 102, 103,  -1,  -1}}, // 13
776 {{   3,   0, 101, 102,   3,   0, 102,   3,   3, 102, 103,   3,  -1,  -1}}, // 14
777 {{   4, 100, 101, 102, 103,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 15
778 };
779 
780 static QUAD_CASES quadCasesComplement[] = {
781 {{  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 0
782 {{   3, 100,   0,   3,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 1
783 {{   3, 101,   1,   0,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 2
784 {{   4, 100, 101,   1,   3,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 3
785 {{   3, 102,   2,   1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 4
786 {{   3, 100,   0,   3,   3, 102,   2,   1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 5
787 {{   4, 101, 102,   2,   0,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 6
788 {{   3, 100, 101,   3,   3, 101,   2,   3,   3, 101, 102,   2,  -1,  -1}}, // 7
789 {{   3, 103,   3,   2,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 8
790 {{   4, 100,   0,   2, 103,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 9
791 {{   3, 101,   1,   0,   3, 103,   3,   2,  -1,  -1,  -1,  -1,  -1,  -1}}, // 10
792 {{   3, 100, 101,   1,   3, 100,   1,   2,   3, 100,   2, 103,  -1,  -1}}, // 11
793 {{   4, 102, 103,   3,   1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 12
794 {{   3, 100,   0, 103,   3,   0,   1, 103,   3,   1, 102, 103,  -1,  -1}}, // 13
795 {{   3,   0, 101, 102,   3,   0, 102,   3,   3, 102, 103,   3,  -1,  -1}}, // 14
796 {{   4, 100, 101, 102, 103,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1}}, // 15
797 };
798 
799 //----------------------------------------------------------------------------
800 // Clip this quad using scalar value provided. Like contouring, except
801 // that it cuts the quad to produce other quads and/or triangles.
Clip(double value,vtkDataArray * cellScalars,vtkIncrementalPointLocator * locator,vtkCellArray * polys,vtkPointData * inPd,vtkPointData * outPd,vtkCellData * inCd,vtkIdType cellId,vtkCellData * outCd,int insideOut)802 void vtkQuad::Clip(double value, vtkDataArray *cellScalars,
803                    vtkIncrementalPointLocator *locator, vtkCellArray *polys,
804                    vtkPointData *inPd, vtkPointData *outPd,
805                    vtkCellData *inCd, vtkIdType cellId, vtkCellData *outCd,
806                    int insideOut)
807 {
808   static int CASE_MASK[4] = {1,2,4,8};
809   QUAD_CASES *quadCase;
810   QUAD_EDGE_LIST  *edge;
811   int i, j, index, *vert;
812   int e1, e2;
813   int newCellId;
814   vtkIdType pts[4];
815   int vertexId;
816   double t, x1[3], x2[3], x[3], deltaScalar;
817   double scalar0, scalar1, e1Scalar;
818 
819   // Build the index into the case table
820   if ( insideOut )
821     {
822     for ( i=0, index = 0; i < 4; i++)
823       {
824       if (cellScalars->GetComponent(i,0) <= value)
825         {
826         index |= CASE_MASK[i];
827         }
828       }
829     // Select case based on the index and get the list of edges for this case
830     quadCase = quadCases + index;
831     }
832   else
833     {
834     for ( i=0, index = 0; i < 4; i++)
835       {
836       if (cellScalars->GetComponent(i,0) > value)
837         {
838         index |= CASE_MASK[i];
839         }
840       }
841     // Select case based on the index and get the list of edges for this case
842     quadCase = quadCasesComplement + index;
843     }
844 
845   edge = quadCase->edges;
846 
847   // generate each quad
848   for ( ; edge[0] > -1; edge += edge[0]+1 )
849     {
850     for (i=0; i < edge[0]; i++) // insert quad or triangle
851       {
852       // vertex exists, and need not be interpolated
853       if (edge[i+1] >= 100)
854         {
855         vertexId = edge[i+1] - 100;
856         this->Points->GetPoint(vertexId, x);
857         if ( locator->InsertUniquePoint(x, pts[i]) )
858           {
859           outPd->CopyData(inPd,this->PointIds->GetId(vertexId),pts[i]);
860           }
861         }
862 
863       else //new vertex, interpolate
864         {
865         vert = edges[edge[i+1]];
866 
867         // calculate a preferred interpolation direction
868         scalar0 = cellScalars->GetComponent(vert[0],0);
869         scalar1 = cellScalars->GetComponent(vert[1],0);
870         deltaScalar = scalar1 - scalar0;
871 
872         if (deltaScalar > 0)
873           {
874           e1 = vert[0]; e2 = vert[1];
875           e1Scalar = scalar0;
876           }
877         else
878           {
879           e1 = vert[1]; e2 = vert[0];
880           e1Scalar = scalar1;
881           deltaScalar = -deltaScalar;
882           }
883 
884         // linear interpolation
885         if (deltaScalar == 0.0)
886           {
887           t = 0.0;
888           }
889         else
890           {
891           t = (value - e1Scalar) / deltaScalar;
892           }
893 
894         this->Points->GetPoint(e1, x1);
895         this->Points->GetPoint(e2, x2);
896 
897         for (j=0; j<3; j++)
898           {
899           x[j] = x1[j] + t * (x2[j] - x1[j]);
900           }
901 
902         if ( locator->InsertUniquePoint(x, pts[i]) )
903           {
904           vtkIdType p1 = this->PointIds->GetId(e1);
905           vtkIdType p2 = this->PointIds->GetId(e2);
906           outPd->InterpolateEdge(inPd,pts[i],p1,p2,t);
907           }
908         }
909       }
910     // check for degenerate output
911     if ( edge[0] == 3 ) //i.e., a triangle
912       {
913       if (pts[0] == pts[1] || pts[0] == pts[2] || pts[1] == pts[2] )
914         {
915         continue;
916         }
917       }
918     else // a quad
919       {
920       if ((pts[0] == pts[3] && pts[1] == pts[2]) ||
921           (pts[0] == pts[1] && pts[3] == pts[2]) )
922         {
923         continue;
924         }
925       }
926 
927     newCellId = polys->InsertNextCell(edge[0],pts);
928     outCd->CopyData(inCd,cellId,newCellId);
929     }
930 }
931 
932 //----------------------------------------------------------------------------
933 static double vtkQuadCellPCoords[12] = {0.0,0.0,0.0, 1.0,0.0,0.0,
934                                        1.0,1.0,0.0, 0.0,1.0,0.0};
GetParametricCoords()935 double *vtkQuad::GetParametricCoords()
936 {
937   return vtkQuadCellPCoords;
938 }
939 
940 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)941 void vtkQuad::PrintSelf(ostream& os, vtkIndent indent)
942 {
943   this->Superclass::PrintSelf(os,indent);
944 
945   os << indent << "Line:\n";
946   this->Line->PrintSelf(os,indent.GetNextIndent());
947   os << indent << "Triangle:\n";
948   this->Triangle->PrintSelf(os,indent.GetNextIndent());
949 }
950