1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkQuadricDecimation.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 // Comments from Brad---
16 // FIXME: I do not have a very good method for detecting the stability of a
17 // matrix
18 
19 // FIXME: improve the combination of boundary constraints and texture
20 // coordinates
21 
22 // FIXME: I want to turn off copying an attribute by default and then enable
23 // it in the ComputeNumberOfComponets function
24 
25 // ISSUE: CheckPlacement is not really a manifold check, should there be a
26 // topological manifold check?
27 
28 // ISSUE: I know I use to think that there was an error in the way Hugues
29 // desribed the area coefficient, but it now seems wrong to me and seems to
30 // produce better results with it not squared, may be this should be some
31 // kind of user parameter? Both seem useful ie uniform area vs. more
32 // curvature dependent
33 
34 // ISSUE: policy on attributes, normals should be renomrlized, should texture
35 // coordinates be clamped?  or just indicate that one might want to use the
36 // array calculator to fix these?
37 
38 // ISSUE: the initial value of the Attribute weights is one, this is generally
39 // not useful, ussually set around .1, but I did this because the the
40 // toggling on and off sets it to 1 and 0
41 
42 #include "vtkQuadricDecimation.h"
43 #include "vtkCellArray.h"
44 #include "vtkCellData.h"
45 #include "vtkEdgeTable.h"
46 #include "vtkDoubleArray.h"
47 #include "vtkGenericCell.h"
48 #include "vtkIdList.h"
49 #include "vtkMath.h"
50 #include "vtkInformation.h"
51 #include "vtkInformationVector.h"
52 #include "vtkObjectFactory.h"
53 #include "vtkPolyData.h"
54 #include "vtkPointData.h"
55 #include "vtkPriorityQueue.h"
56 #include "vtkTriangle.h"
57 
58 vtkStandardNewMacro(vtkQuadricDecimation);
59 
60 
61 //----------------------------------------------------------------------------
vtkQuadricDecimation()62 vtkQuadricDecimation::vtkQuadricDecimation()
63 {
64   this->Edges = vtkEdgeTable::New();
65   this->EdgeCosts = vtkPriorityQueue::New();
66   this->EndPoint1List = vtkIdList::New();
67   this->EndPoint2List = vtkIdList::New();
68   this->ErrorQuadrics = NULL;
69   this->TargetPoints = vtkDoubleArray::New();
70 
71   this->TargetReduction = 0.9;
72   this->NumberOfEdgeCollapses = 0;
73   this->NumberOfComponents = 0;
74 
75   this->AttributeErrorMetric = 0;
76   this->ScalarsAttribute = 1;
77   this->VectorsAttribute = 1;
78   this->NormalsAttribute = 1;
79   this->TCoordsAttribute = 1;
80   this->TensorsAttribute = 1;
81 
82   this->ScalarsWeight = 0.1;
83   this->VectorsWeight = 0.1;
84   this->NormalsWeight = 0.1;
85   this->TCoordsWeight = 0.1;
86   this->TensorsWeight = 0.1;
87 
88   this->ActualReduction = 0.0;
89 }
90 
91 //----------------------------------------------------------------------------
~vtkQuadricDecimation()92 vtkQuadricDecimation::~vtkQuadricDecimation()
93 {
94   this->Edges->Delete();
95   this->EdgeCosts->Delete();
96   this->EndPoint1List->Delete();
97   this->EndPoint2List->Delete();
98   this->TargetPoints->Delete();
99 }
100 
SetPointAttributeArray(vtkIdType ptId,const double * x)101 void vtkQuadricDecimation::SetPointAttributeArray(vtkIdType ptId,
102                                                   const double *x)
103 {
104   int i;
105   this->Mesh->GetPoints()->SetPoint(ptId, x);
106 
107   for (i = 0; i < this->NumberOfComponents; i++)
108     {
109     if (i < this->AttributeComponents[0])
110       {
111       this->Mesh->GetPointData()->GetScalars()->
112         SetComponent(ptId, i, x[3+i]/this->AttributeScale[0]);
113       }
114     else if (i < this->AttributeComponents[1])
115       {
116       this->Mesh->GetPointData()->GetVectors()->
117         SetComponent(ptId, i-this->AttributeComponents[0], x[3+i]/this->AttributeScale[1]);
118       }
119     else if (i < this->AttributeComponents[2])
120       {
121       this->Mesh->GetPointData()->GetNormals()->
122         SetComponent(ptId, i-this->AttributeComponents[1], x[3+i]/this->AttributeScale[2]);
123       }
124     else if (i < this->AttributeComponents[3])
125       {
126       this->Mesh->GetPointData()->GetTCoords()->
127         SetComponent(ptId, i-this->AttributeComponents[2], x[3+i]/this->AttributeScale[3]);
128       }
129     else if (i < this->AttributeComponents[4])
130       {
131       this->Mesh->GetPointData()->GetTensors()->
132         SetComponent(ptId, i-this->AttributeComponents[3], x[3+i]/this->AttributeScale[4]);
133       }
134     }
135 }
136 
GetPointAttributeArray(vtkIdType ptId,double * x)137 void vtkQuadricDecimation::GetPointAttributeArray(vtkIdType ptId, double *x)
138 {
139   int i;
140   this->Mesh->GetPoints()->GetPoint(ptId, x);
141 
142   for (i = 0; i < this->NumberOfComponents; i++)
143     {
144     if (i < this->AttributeComponents[0])
145       {
146       x[3+i] = this->Mesh->GetPointData()->GetScalars()->
147         GetComponent(ptId, i) *  this->AttributeScale[0];
148       }
149     else if (i < this->AttributeComponents[1])
150       {
151       x[3+i] = this->Mesh->GetPointData()->GetVectors()->
152         GetComponent(ptId, i-this->AttributeComponents[0]) *  this->AttributeScale[1];
153       }
154     else if (i < this->AttributeComponents[2])
155       {
156       x[3+i] = this->Mesh->GetPointData()->GetNormals()->
157         GetComponent(ptId, i-this->AttributeComponents[1]) *  this->AttributeScale[2];
158       }
159     else if (i < this->AttributeComponents[3])
160       {
161       x[3+i] = this->Mesh->GetPointData()->GetTCoords()->
162         GetComponent(ptId, i-this->AttributeComponents[2]) *  this->AttributeScale[3];
163       }
164     else if (i < this->AttributeComponents[4])
165       {
166       x[3+i] = this->Mesh->GetPointData()->GetTensors()->
167         GetComponent(ptId, i-this->AttributeComponents[3]) *  this->AttributeScale[4];
168       }
169     }
170 }
171 
172 //----------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)173 int vtkQuadricDecimation::RequestData(
174   vtkInformation *vtkNotUsed(request),
175   vtkInformationVector **inputVector,
176   vtkInformationVector *outputVector)
177 {
178   // get the info objects
179   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
180   vtkInformation *outInfo = outputVector->GetInformationObject(0);
181 
182   // get the input and output
183   vtkPolyData *input = vtkPolyData::SafeDownCast(
184     inInfo->Get(vtkDataObject::DATA_OBJECT()));
185   vtkPolyData *output = vtkPolyData::SafeDownCast(
186     outInfo->Get(vtkDataObject::DATA_OBJECT()));
187 
188   vtkIdType numPts = input->GetNumberOfPoints();
189   vtkIdType numTris = input->GetNumberOfPolys();
190   vtkIdType edgeId, i;
191   int j;
192   double cost;
193   double *x;
194   vtkCellArray *polys;
195   vtkDataArray *attrib;
196   vtkPoints *points;
197   vtkPointData *pointData;
198   vtkIdType endPtIds[2];
199   vtkIdList *outputCellList;
200   vtkIdType npts, *pts;
201   vtkIdType numDeletedTris=0;
202 
203   // check some assuptiona about the data
204   if (input->GetPolys() == NULL || input->GetPoints() == NULL ||
205       input->GetPointData() == NULL  || input->GetFieldData() == NULL)
206     {
207     vtkErrorMacro("Nothing to decimate");
208     return 1;
209     }
210 
211   if (input->GetPolys()->GetMaxCellSize() > 3)
212     {
213     vtkErrorMacro("Can only decimate triangles");
214     return 1;
215     }
216 
217   polys = vtkCellArray::New();
218   points = vtkPoints::New();
219   pointData = vtkPointData::New();
220   outputCellList = vtkIdList::New();
221 
222   // copy the input (only polys) to our working mesh
223   this->Mesh = vtkPolyData::New();
224   points->DeepCopy(input->GetPoints());
225   this->Mesh->SetPoints(points);
226   points->Delete();
227   polys->DeepCopy(input->GetPolys());
228   this->Mesh->SetPolys(polys);
229   polys->Delete();
230   if (this->AttributeErrorMetric)
231     {
232     this->Mesh->GetPointData()->DeepCopy(input->GetPointData());
233     }
234   pointData->Delete();
235   this->Mesh->GetFieldData()->PassData(input->GetFieldData());
236   this->Mesh->BuildCells();
237   this->Mesh->BuildLinks();
238 
239   this->ErrorQuadrics =
240     new vtkQuadricDecimation::ErrorQuadric[numPts];
241 
242   vtkDebugMacro(<<"Computing Edges");
243   this->Edges->InitEdgeInsertion(numPts, 1); // storing edge id as attribute
244   this->EdgeCosts->Allocate(this->Mesh->GetPolys()->GetNumberOfCells() * 3);
245   for (i = 0; i <  this->Mesh->GetNumberOfCells(); i++)
246     {
247     this->Mesh->GetCellPoints(i, npts, pts);
248 
249     for (j = 0; j < 3; j++)
250       {
251       if (this->Edges->IsEdge(pts[j], pts[(j+1)%3]) == -1)
252         {
253         // If this edge has not been processed, get an id for it, add it to
254         // the edge list (Edges), and add its endpoints to the EndPoint1List
255         // and EndPoint2List (the 2 endpoints to different lists).
256         edgeId = this->Edges->GetNumberOfEdges();
257         this->Edges->InsertEdge(pts[j], pts[(j+1)%3], edgeId);
258         this->EndPoint1List->InsertId(edgeId, pts[j]);
259         this->EndPoint2List->InsertId(edgeId, pts[(j+1)%3]);
260         }
261       }
262     }
263 
264   this->UpdateProgress(0.1);
265 
266   this->NumberOfComponents = 0;
267   if (this->AttributeErrorMetric)
268     {
269     this->ComputeNumberOfComponents();
270     }
271   x = new double [3+this->NumberOfComponents];
272   this->CollapseCellIds = vtkIdList::New();
273   this->TempX = new double [3+this->NumberOfComponents];
274   this->TempQuad = new double[11 + 4 * this->NumberOfComponents];
275 
276   this->TempB = new double [3 +  this->NumberOfComponents];
277   this->TempA = new double*[3 +  this->NumberOfComponents];
278   this->TempData = new double [(3 +  this->NumberOfComponents)*(3 +  this->NumberOfComponents)];
279   for (i = 0; i < 3 +  this->NumberOfComponents; i++)
280     {
281     this->TempA[i] = this->TempData+i*(3 +  this->NumberOfComponents);
282     }
283   this->TargetPoints->SetNumberOfComponents(3+this->NumberOfComponents);
284 
285   vtkDebugMacro(<<"Computing Quadrics");
286   this->InitializeQuadrics(numPts);
287   this->AddBoundaryConstraints();
288   this->UpdateProgress(0.15);
289 
290   vtkDebugMacro(<<"Computing Costs");
291   // Compute the cost of and target point for collapsing each edge.
292   for (i = 0; i < this->Edges->GetNumberOfEdges(); i++)
293     {
294     if (this->AttributeErrorMetric)
295       {
296       cost = this->ComputeCost2(i, x);
297       }
298     else
299       {
300       cost = this->ComputeCost(i, x);
301       }
302     this->EdgeCosts->Insert(cost, i);
303     this->TargetPoints->InsertTuple(i, x);
304     }
305   this->UpdateProgress(0.20);
306 
307   // Okay collapse edges until desired reduction is reached
308   this->ActualReduction = 0.0;
309   this->NumberOfEdgeCollapses = 0;
310   edgeId = this->EdgeCosts->Pop(0,cost);
311 
312   int abort = 0;
313   while ( !abort && edgeId >= 0 && cost < VTK_DOUBLE_MAX &&
314          this->ActualReduction < this->TargetReduction )
315     {
316     if ( ! (this->NumberOfEdgeCollapses % 10000) )
317       {
318       vtkDebugMacro(<<"Collapsing edge#" << this->NumberOfEdgeCollapses);
319       this->UpdateProgress (0.20 + 0.80*this->NumberOfEdgeCollapses/numPts);
320       abort = this->GetAbortExecute();
321       }
322 
323     endPtIds[0] = this->EndPoint1List->GetId(edgeId);
324     endPtIds[1] = this->EndPoint2List->GetId(edgeId);
325     this->TargetPoints->GetTuple(edgeId, x);
326 
327     // check for a poorly placed point
328     if ( !this->IsGoodPlacement(endPtIds[0], endPtIds[1], x))
329       {
330       vtkDebugMacro(<<"Poor placement detected " << edgeId << " " <<  cost);
331       // return the point to the queue but with the max cost so that
332       // when it is recomputed it will be reconsidered
333       this->EdgeCosts->Insert(VTK_DOUBLE_MAX, edgeId);
334 
335       edgeId = this->EdgeCosts->Pop(0, cost);
336       continue;
337       }
338 
339     this->NumberOfEdgeCollapses++;
340 
341     // Set the new coordinates of point0.
342     this->SetPointAttributeArray(endPtIds[0], x);
343     vtkDebugMacro(<<"Cost: " << cost << " Edge: "
344                   << endPtIds[0] << " " << endPtIds[1]);
345 
346     // Merge the quadrics of the two points.
347     this->AddQuadric(endPtIds[1], endPtIds[0]);
348 
349     this->UpdateEdgeData(endPtIds[0], endPtIds[1]);
350 
351     // Update the output triangles.
352     numDeletedTris += this->CollapseEdge(endPtIds[0], endPtIds[1]);
353     this->ActualReduction = (double) numDeletedTris / numTris;
354     edgeId = this->EdgeCosts->Pop(0, cost);
355     }
356 
357   vtkDebugMacro(<<"Number Of Edge Collapses: "
358                 << this->NumberOfEdgeCollapses << " Cost: " << cost);
359 
360   // clean up working data
361   for (i = 0; i < numPts; i++)
362     {
363     delete [] this->ErrorQuadrics[i].Quadric;
364     }
365   delete [] this->ErrorQuadrics;
366   delete [] x;
367   this->CollapseCellIds->Delete();
368   delete [] this->TempX;
369   delete [] this->TempQuad;
370   delete [] this->TempB;
371   delete [] this->TempA;
372   delete [] this->TempData;
373 
374   // copy the simplified mesh from the working mesh to the output mesh
375   for (i = 0; i < this->Mesh->GetNumberOfCells(); i++)
376     {
377     if (this->Mesh->GetCell(i)->GetCellType() != VTK_EMPTY_CELL)
378       {
379       outputCellList->InsertNextId(i);
380       }
381     }
382 
383   output->Reset();
384   output->Allocate(this->Mesh, outputCellList->GetNumberOfIds());
385   output->GetPointData()->CopyAllocate(this->Mesh->GetPointData(),1);
386   output->CopyCells(this->Mesh, outputCellList);
387 
388   this->Mesh->DeleteLinks();
389   this->Mesh->Delete();
390   outputCellList->Delete();
391 
392   // renormalize, clamp attributes
393   if (this->AttributeErrorMetric)
394     {
395     if (NULL != (attrib = output->GetPointData()->GetNormals()))
396       {
397       for (i = 0; i < attrib->GetNumberOfTuples(); i++)
398         {
399         vtkMath::Normalize(attrib->GetTuple3(i));
400         }
401       }
402     // might want to add clamping texture coordinates??
403     }
404 
405   return 1;
406 }
407 
408 //----------------------------------------------------------------------------
InitializeQuadrics(vtkIdType numPts)409 void vtkQuadricDecimation::InitializeQuadrics(vtkIdType numPts)
410 {
411   vtkPolyData *input = this->Mesh;
412   double *QEM;
413   vtkIdType ptId;
414   int i, j;
415   vtkCellArray *polys;
416   vtkIdType npts, *pts=NULL;
417   double point0[3], point1[3], point2[3];
418   double n[3];
419   double tempP1[3], tempP2[3],  d, triArea2;
420   double data[16];
421   double *A[4], x[4];
422   int index[4];
423   A[0] = data;
424   A[1] = data+4;
425   A[2] = data+8;
426   A[3] = data+12;
427 
428   // allocate local QEM sparce matrix
429   QEM = new double[11 + 4 * this->NumberOfComponents];
430 
431   // clear and allocate global QEM array
432   for (ptId = 0; ptId < numPts; ptId++)
433     {
434     this->ErrorQuadrics[ptId].Quadric =
435       new double[11 + 4 * this->NumberOfComponents];
436     for (i = 0; i < 11 + 4 * this->NumberOfComponents; i++)
437       {
438       this->ErrorQuadrics[ptId].Quadric[i] = 0.0;
439       }
440     }
441 
442   polys = input->GetPolys();
443   // compute the QEM for each face
444   for (polys->InitTraversal(); polys->GetNextCell(npts, pts); )
445     {
446     input->GetPoint(pts[0], point0);
447     input->GetPoint(pts[1], point1);
448     input->GetPoint(pts[2], point2);
449     for (i = 0; i < 3; i++)
450       {
451       tempP1[i] = point1[i] - point0[i];
452       tempP2[i] = point2[i] - point0[i];
453       }
454     vtkMath::Cross(tempP1, tempP2, n);
455     triArea2 = vtkMath::Normalize(n);
456     //triArea2 = (triArea2 * triArea2 * 0.25);
457     triArea2 = triArea2 * 0.5;
458     // I am unsure whether this should be squared or not??
459     d = -vtkMath::Dot(n, point0);
460     // could possible add in angle weights??
461 
462     // set the geometric part of the QEM
463     QEM[0] = n[0] * n[0];
464     QEM[1] = n[0] * n[1];
465     QEM[2] = n[0] * n[2];
466     QEM[3] = d * n[0];
467 
468     QEM[4] = n[1] * n[1];
469     QEM[5] = n[1] * n[2];
470     QEM[6] = d * n[1];
471 
472     QEM[7] = n[2] * n[2];
473     QEM[8] = d * n[2];
474 
475     QEM[9] = d * d;
476     QEM[10] = 1;
477 
478     if (this->AttributeErrorMetric)
479       {
480       for (i = 0; i < 3; i++)
481         {
482         A[0][i] = point0[i];
483         A[1][i] = point1[i];
484         A[2][i] = point2[i];
485         A[3][i] = n[i];
486         }
487       A[0][3] =  A[1][3] = A[2][3] = 1;
488       A[3][3] = 0;
489 
490       // should handle poorly condition matrix better
491       if (vtkMath::LUFactorLinearSystem(A, index, 4))
492         {
493         for (i = 0; i < this->NumberOfComponents; i++)
494           {
495           x[3] = 0;
496           if (i < this->AttributeComponents[0])
497             {
498             x[0] = input->GetPointData()->GetScalars()->GetComponent(pts[0], i) *  this->AttributeScale[0];
499             x[1] = input->GetPointData()->GetScalars()->GetComponent(pts[1], i) *  this->AttributeScale[0];
500             x[2] = input->GetPointData()->GetScalars()->GetComponent(pts[2], i) *  this->AttributeScale[0];
501             }
502           else if (i < this->AttributeComponents[1])
503             {
504             x[0] = input->GetPointData()->GetVectors()->GetComponent(pts[0], i - this->AttributeComponents[0]) *  this->AttributeScale[1];
505             x[1] = input->GetPointData()->GetVectors()->GetComponent(pts[1], i - this->AttributeComponents[0]) *  this->AttributeScale[1];
506             x[2] = input->GetPointData()->GetVectors()->GetComponent(pts[2], i - this->AttributeComponents[0]) *  this->AttributeScale[1];
507             }
508           else if (i < this->AttributeComponents[2])
509             {
510             x[0] = input->GetPointData()->GetNormals()->GetComponent(pts[0], i - this->AttributeComponents[1]) *  this->AttributeScale[2];
511             x[1] = input->GetPointData()->GetNormals()->GetComponent(pts[1], i - this->AttributeComponents[1]) *  this->AttributeScale[2];
512             x[2] = input->GetPointData()->GetNormals()->GetComponent(pts[2], i - this->AttributeComponents[1]) *  this->AttributeScale[2];
513             }
514           else if (i < this->AttributeComponents[3])
515             {
516             x[0] = input->GetPointData()->GetTCoords()->GetComponent(pts[0], i - this->AttributeComponents[2]) *  this->AttributeScale[3];
517             x[1] = input->GetPointData()->GetTCoords()->GetComponent(pts[1], i - this->AttributeComponents[2])*  this->AttributeScale[3];
518             x[2] = input->GetPointData()->GetTCoords()->GetComponent(pts[2], i - this->AttributeComponents[2])*  this->AttributeScale[3];
519             }
520           else if (i < this->AttributeComponents[4])
521             {
522             x[0] = input->GetPointData()->GetTensors()->GetComponent(pts[0], i - this->AttributeComponents[3])*  this->AttributeScale[4];
523             x[1] = input->GetPointData()->GetTensors()->GetComponent(pts[1], i - this->AttributeComponents[3])*  this->AttributeScale[4];
524             x[2] = input->GetPointData()->GetTensors()->GetComponent(pts[2], i - this->AttributeComponents[3])*  this->AttributeScale[4];
525             }
526           vtkMath::LUSolveLinearSystem(A, index, x, 4);
527 
528           // add in the contribution of this element into the QEM
529           QEM[0] += x[0] * x[0];
530           QEM[1] += x[0] * x[1];
531           QEM[2] += x[0] * x[2];
532           QEM[3] += x[3] * x[0];
533 
534           QEM[4] += x[1] * x[1];
535           QEM[5] += x[1] * x[2];
536           QEM[6] += x[3] * x[1];
537 
538           QEM[7] += x[2] * x[2];
539           QEM[8] += x[3] * x[2];
540 
541           QEM[9] += x[3] * x[3];
542 
543           QEM[11+i*4] = -x[0];
544           QEM[12+i*4] = -x[1];
545           QEM[13+i*4] = -x[2];
546           QEM[14+i*4] = -x[3];
547           }
548         }
549       else
550         {
551         vtkErrorMacro(<<"Unable to factor attribute matrix!");
552         }
553       }
554 
555       // add the QEM to all point of the face
556     for (i = 0; i < 3; i++)
557       {
558       for (j = 0; j < 11 + 4 * this->NumberOfComponents; j++)
559         {
560         this->ErrorQuadrics[pts[i]].Quadric[j] += QEM[j] * triArea2;
561         }
562       }
563     }//for all triangles
564 
565   delete [] QEM;
566 }
567 
568 
AddBoundaryConstraints(void)569 void vtkQuadricDecimation::AddBoundaryConstraints(void)
570 {
571   vtkPolyData *input = this->Mesh;
572   double *QEM;
573   vtkIdType  cellId;
574   int i, j;
575   vtkIdType npts, *pts;
576   double t0[3], t1[3], t2[3];
577   double e0[3], e1[3], n[3], c, d, w;
578   vtkIdList *cellIds = vtkIdList::New();
579 
580   // allocate local QEM space matrix
581   QEM = new double[11 + 4 * this->NumberOfComponents];
582 
583   for (cellId = 0; cellId < input->GetNumberOfCells(); cellId++)
584     {
585     input->GetCellPoints(cellId, npts, pts);
586 
587     for (i = 0; i < 3; i++)
588       {
589       input->GetCellEdgeNeighbors(cellId, pts[i], pts[(i+1)%3], cellIds);
590       if (cellIds->GetNumberOfIds() == 0)
591         {
592         // this is a boundary
593         input->GetPoint(pts[(i+2)%3], t0);
594         input->GetPoint(pts[i], t1);
595         input->GetPoint(pts[(i+1)%3], t2);
596 
597         // computing a plane which is orthogonal to line t1, t2 and incident
598         // with it
599         for (j = 0; j < 3; j++)
600           {
601           e0[j] = t2[j] - t1[j];
602           }
603         for (j = 0; j < 3; j++)
604           {
605           e1[j] = t0[j] - t1[j];
606           }
607 
608         // compute n so that it is orthogonal to e0 and parallel to the
609         // triangle
610         c = vtkMath::Dot(e0,e1)/(e0[0]*e0[0]+e0[1]*e0[1]+e0[2]*e0[2]);
611         for (j = 0; j < 3; j++)
612           {
613           n[j] = e1[j] - c*e0[j];
614           }
615         vtkMath::Normalize(n);
616         d = -vtkMath::Dot(n, t1);
617         w = vtkMath::Norm(e0);
618 
619         //w *= w;
620         // area issue ??
621         // could possible add in angle weights??
622         QEM[0] = n[0] * n[0];
623         QEM[1] = n[0] * n[1];
624         QEM[2] = n[0] * n[2];
625         QEM[3] = d * n[0];
626 
627         QEM[4] = n[1] * n[1];
628         QEM[5] = n[1] * n[2];
629         QEM[6] = d * n[1];
630 
631         QEM[7] = n[2] * n[2];
632         QEM[8] = d * n[2];
633 
634         QEM[9] = d * d;
635 
636         QEM[10] = 1;
637 
638         // need to add orthogonal plane with the other Attributes, but this
639         // is not clear??
640         // check to interaction with attribute data
641         for (j = 0; j < 11; j++)
642           {
643           this->ErrorQuadrics[pts[i]].Quadric[j] += QEM[j]*w;
644           this->ErrorQuadrics[pts[(i+1)%3]].Quadric[j] += QEM[j]*w;
645           }
646         }
647       }
648     }
649   cellIds->Delete();
650   delete [] QEM;
651 }
652 
653 //----------------------------------------------------------------------------
AddQuadric(vtkIdType oldPtId,vtkIdType newPtId)654 void vtkQuadricDecimation::AddQuadric(vtkIdType oldPtId, vtkIdType newPtId)
655 {
656   int i;
657 
658   for (i = 0; i < 11 + 4*this->NumberOfComponents; i++)
659     {
660     this->ErrorQuadrics[newPtId].Quadric[i] +=
661       this->ErrorQuadrics[oldPtId].Quadric[i];
662     }
663 }
664 
665 //----------------------------------------------------------------------------
FindAffectedEdges(vtkIdType p1Id,vtkIdType p2Id,vtkIdList * edges)666 void vtkQuadricDecimation::FindAffectedEdges(vtkIdType p1Id, vtkIdType p2Id,
667                                               vtkIdList *edges)
668 {
669   unsigned short ncells;
670   vtkIdType *cells, npts, *pts, edgeId;
671   unsigned short i, j;
672 
673   edges->Reset();
674   this->Mesh->GetPointCells(p2Id, ncells, cells);
675   for (i = 0; i < ncells; i++)
676     {
677     this->Mesh->GetCellPoints(cells[i], npts, pts);
678     for (j = 0; j < 3; j++)
679       {
680       if (pts[j] != p1Id && pts[j] != p2Id &&
681           (edgeId = this->Edges->IsEdge(pts[j], p2Id)) >= 0 &&
682           edges->IsId(edgeId) == -1)
683         {
684         edges->InsertNextId(edgeId);
685         }
686       }
687     }
688 
689   this->Mesh->GetPointCells(p1Id, ncells, cells);
690   for (i = 0; i < ncells; i++)
691     {
692     this->Mesh->GetCellPoints(cells[i], npts, pts);
693     for (j = 0; j < 3; j++)
694       {
695       if (pts[j] != p1Id && pts[j] != p2Id &&
696           (edgeId = this->Edges->IsEdge(pts[j], p1Id)) >= 0 &&
697           edges->IsId(edgeId) == -1)
698         {
699         edges->InsertNextId(edgeId);
700         }
701       }
702     }
703 }
704 
705 // FIXME: memory allocation clean up
UpdateEdgeData(vtkIdType pt0Id,vtkIdType pt1Id)706 void vtkQuadricDecimation::UpdateEdgeData(vtkIdType pt0Id, vtkIdType pt1Id)
707 {
708   vtkIdList *changedEdges = vtkIdList::New();
709   vtkIdType i, edgeId, edge[2];
710   double cost;
711 
712   // Find all edges with exactly either of these 2 endpoints.
713   this->FindAffectedEdges(pt0Id, pt1Id, changedEdges);
714 
715   // Reset the endpoints for these edges to reflect the new point from the
716   // collapsed edge.
717   // Add these new edges to the edge table.
718   // Remove the the changed edges from the priority queue.
719   for (i = 0; i < changedEdges->GetNumberOfIds(); i++)
720     {
721     edge[0] = this->EndPoint1List->GetId(changedEdges->GetId(i));
722     edge[1] = this->EndPoint2List->GetId(changedEdges->GetId(i));
723 
724     // Remove all affected edges from the priority queue.
725     // This does not include collapsed edge.
726     this->EdgeCosts->DeleteId(changedEdges->GetId(i));
727 
728     // Determine the new set of edges
729     if (edge[0] == pt1Id)
730       {
731       if (this->Edges->IsEdge(edge[1], pt0Id) == -1)
732         { // The edge will be completely new, add it.
733         edgeId = this->Edges->GetNumberOfEdges();
734         this->Edges->InsertEdge(edge[1], pt0Id, edgeId);
735         this->EndPoint1List->InsertId(edgeId, edge[1]);
736         this->EndPoint2List->InsertId(edgeId, pt0Id);
737         // Compute cost (target point/data) and add to priority cue.
738         if (this->AttributeErrorMetric)
739           {
740           cost = this->ComputeCost2(edgeId, this->TempX);
741           }
742         else
743           {
744           cost = this->ComputeCost(edgeId, this->TempX);
745           }
746         this->EdgeCosts->Insert(cost, edgeId);
747         this->TargetPoints->InsertTuple(edgeId, this->TempX);
748         }
749       }
750     else if (edge[1] == pt1Id)
751       { // The edge will be completely new, add it.
752       if (this->Edges->IsEdge(edge[0], pt0Id) == -1)
753         {
754         edgeId = this->Edges->GetNumberOfEdges();
755         this->Edges->InsertEdge(edge[0], pt0Id, edgeId);
756         this->EndPoint1List->InsertId(edgeId, edge[0]);
757         this->EndPoint2List->InsertId(edgeId, pt0Id);
758         // Compute cost (target point/data) and add to priority cue.
759         if (this->AttributeErrorMetric)
760           {
761           cost = this->ComputeCost2(edgeId, this->TempX);
762           }
763         else
764           {
765           cost = this->ComputeCost(edgeId, this->TempX);
766           }
767         this->EdgeCosts->Insert(cost, edgeId);
768         this->TargetPoints->InsertTuple(edgeId, this->TempX);
769         }
770       }
771     else
772       { // This edge already has one point as the merged point.
773       if (this->AttributeErrorMetric)
774         {
775         cost = this->ComputeCost2(changedEdges->GetId(i), this->TempX);
776         }
777       else
778         {
779         cost = this->ComputeCost(changedEdges->GetId(i), this->TempX);
780         }
781       this->EdgeCosts->Insert(cost, changedEdges->GetId(i));
782       this->TargetPoints->InsertTuple(changedEdges->GetId(i), this->TempX);
783       }
784     }
785 
786   changedEdges->Delete();
787   return;
788 }
789 
790 //----------------------------------------------------------------------------
ComputeCost(vtkIdType edgeId,double * x)791 double vtkQuadricDecimation::ComputeCost(vtkIdType edgeId, double *x)
792 {
793   static const double errorNumber = 1e-10;
794   double temp[3], A[3][3], b[3];
795   vtkIdType pointIds[2];
796   double cost = 0.0;
797   double *index;
798   int i, j;
799   double newPoint [4];
800   double v[3],  c, norm, normTemp,  temp2[3];
801   double pt1[3], pt2[3];
802 
803   pointIds[0] = this->EndPoint1List->GetId(edgeId);
804   pointIds[1] = this->EndPoint2List->GetId(edgeId);
805 
806   for (i = 0; i < 11 + 4 * this->NumberOfComponents; i++)
807     {
808     this->TempQuad[i] = this->ErrorQuadrics[pointIds[0]].Quadric[i] +
809       this->ErrorQuadrics[pointIds[1]].Quadric[i];
810     }
811 
812   A[0][0] = this->TempQuad[0];
813   A[0][1] = A[1][0] = this->TempQuad[1];
814   A[0][2] = A[2][0] = this->TempQuad[2];
815   A[1][1] = this->TempQuad[4];
816   A[1][2] = A[2][1] = this->TempQuad[5];
817   A[2][2] = this->TempQuad[7];
818 
819   b[0] = -this->TempQuad[3];
820   b[1] = -this->TempQuad[6];
821   b[2] = -this->TempQuad[8];
822 
823   norm = vtkMath::Norm(A[0]);
824   normTemp = vtkMath::Norm(A[1]);
825   norm = norm > normTemp ? norm : normTemp;
826   normTemp = vtkMath::Norm(A[2]);
827   norm = norm > normTemp ? norm : normTemp;
828 
829   if (fabs(vtkMath::Determinant3x3(A))/(norm*norm*norm) >  errorNumber)
830     {
831     // it would be better to use the normal of the matrix to test singularity??
832     vtkMath::LinearSolve3x3(A, b, x);
833     vtkMath::Multiply3x3(A,x,temp);
834     // error too high, backup plans
835     }
836   else
837     {
838     // cheapest point along the edge
839     this->Mesh->GetPoints()->GetPoint(pointIds[0], pt1);
840     this->Mesh->GetPoints()->GetPoint(pointIds[1], pt2);
841     v[0] = pt2[0] - pt1[0];
842     v[1] = pt2[1] - pt1[1];
843     v[2] = pt2[2] - pt1[2];
844 
845     // equation for the edge pt1 + c * v
846     // attempt least squares fit for c for A*(pt1 + c * v) = b
847     vtkMath::Multiply3x3(A,v,temp2);
848     if (vtkMath::Dot(temp2, temp2) > errorNumber)
849       {
850       vtkMath::Multiply3x3(A,pt1,temp);
851       for (i = 0; i < 3; i++)
852         temp[i] = b[i] - temp[i];
853       c = vtkMath::Dot(temp2, temp) / vtkMath::Dot(temp2, temp2);
854       for (i = 0; i < 3; i++)
855         x[i] = pt1[i]+c*v[i];
856       }
857     else
858       {
859       // use mid point
860       // might want to change to best of mid and end points??
861       for (i = 0; i < 3; i++)
862         {
863         x[i] = 0.5*(pt1[i]+pt2[i]);
864         }
865       }
866     }
867 
868   newPoint[0] = x[0];
869   newPoint[1] = x[1];
870   newPoint[2] = x[2];
871   newPoint[3] = 1;
872 
873   // Compute the cost
874   // x'*quad*x
875   index = this->TempQuad;
876   for (i = 0; i < 4; i++)
877     {
878     cost += (*index++)*newPoint[i]*newPoint[i];
879     for (j = i +1; j < 4; j++)
880       {
881       cost += 2.0*(*index++)*newPoint[i]*newPoint[j];
882       }
883     }
884 
885   return cost;
886 }
887 
888 
889 //----------------------------------------------------------------------------
ComputeCost2(vtkIdType edgeId,double * x)890 double vtkQuadricDecimation::ComputeCost2(vtkIdType edgeId, double *x)
891 {
892   // this function is so ugly because the functionality of converting an QEM
893   // into a dence matrix was not extracted into a separate function and
894   // neither was multiplication and some other matrix and vector primitives
895   static const double errorNumber = 1e-10;
896   vtkIdType pointIds[2];
897   double cost = 0.0;
898   int i, j;
899   int solveOk;
900 
901   pointIds[0] = this->EndPoint1List->GetId(edgeId);
902   pointIds[1] = this->EndPoint2List->GetId(edgeId);
903 
904   for (i = 0; i < 11 + 4 * this->NumberOfComponents; i++)
905     {
906     this->TempQuad[i] = this->ErrorQuadrics[pointIds[0]].Quadric[i] +
907       this->ErrorQuadrics[pointIds[1]].Quadric[i];
908     }
909 
910   // copy the temp quad into TempA
911   // converting from the sparce matrix format into a dence
912   this->TempA[0][0] = this->TempQuad[0];
913   this->TempA[0][1] = this->TempA[1][0] = this->TempQuad[1];
914   this->TempA[0][2] = this->TempA[2][0] = this->TempQuad[2];
915   this->TempA[1][1] = this->TempQuad[4];
916   this->TempA[1][2] = this->TempA[2][1] = this->TempQuad[5];
917   this->TempA[2][2] = this->TempQuad[7];
918 
919   this->TempB[0] = -this->TempQuad[3];
920   this->TempB[1] = -this->TempQuad[6];
921   this->TempB[2] = -this->TempQuad[8];
922 
923   for (i = 3; i < 3 +  this->NumberOfComponents; i++)
924     {
925     this->TempA[0][i] = this->TempA[i][0] = this->TempQuad[11+4*(i-3)];
926     this->TempA[1][i] = this->TempA[i][1] = this->TempQuad[11+4*(i-3)+1];
927     this->TempA[2][i] = this->TempA[i][2] = this->TempQuad[11+4*(i-3)+2];
928     this->TempB[i] = -this->TempQuad[11+4*(i-3)+3];
929     }
930 
931   for (i = 3; i < 3 +  this->NumberOfComponents; i++)
932     {
933     for (j = 3; j < 3 +  this->NumberOfComponents; j++)
934       {
935       if (i == j)
936         {
937         this->TempA[i][j] = this->TempQuad[10];
938         }
939       else
940         {
941         this->TempA[i][j] = 0;
942         }
943       }
944     }
945 
946   for (i = 0; i < 3 + this->NumberOfComponents; i++)
947     {
948     x[i] = this->TempB[i];
949     }
950 
951   // solve A*x = b
952   // this clobers A
953   // need to develop a quality of the solution test??
954   solveOk = vtkMath::SolveLinearSystem(this->TempA, x, 3 +  this->NumberOfComponents);
955 
956   // need to copy back into A
957   this->TempA[0][0] = this->TempQuad[0];
958   this->TempA[0][1] = this->TempA[1][0] = this->TempQuad[1];
959   this->TempA[0][2] = this->TempA[2][0] = this->TempQuad[2];
960   this->TempA[1][1] = this->TempQuad[4];
961   this->TempA[1][2] = this->TempA[2][1] = this->TempQuad[5];
962   this->TempA[2][2] = this->TempQuad[7];
963 
964   for (i = 3; i < 3 +  this->NumberOfComponents; i++)
965     {
966     this->TempA[0][i] = this->TempA[i][0] = this->TempQuad[11+4*(i-3)];
967     this->TempA[1][i] = this->TempA[i][1] = this->TempQuad[11+4*(i-3)+1];
968     this->TempA[2][i] = this->TempA[i][2] = this->TempQuad[11+4*(i-3)+2];
969     }
970 
971   for (i = 3; i < 3 +  this->NumberOfComponents; i++)
972     {
973     for (j = 3; j < 3 +  this->NumberOfComponents; j++)
974       {
975       if (i == j)
976         {
977         this->TempA[i][j] = this->TempQuad[10];
978         }
979       else
980         {
981         this->TempA[i][j] = 0;
982         }
983       }
984     }
985 
986   // check for failure to solve the system
987   if (!solveOk)
988     {
989     // cheapest point along the edge
990     // this should not frequently occur, so I am using dynamic allocation
991     double *pt1 = new double [3+this->NumberOfComponents];
992     double *pt2 = new double [3+this->NumberOfComponents];
993     double *v = new double [3+this->NumberOfComponents];
994     double *temp = new double [3+this->NumberOfComponents];
995     double *temp2 = new double [3+this->NumberOfComponents];
996     double d = 0;
997     double c = 0;
998 
999     this->GetPointAttributeArray(pointIds[0], pt1);
1000     this->GetPointAttributeArray(pointIds[1], pt2);
1001     for (i = 0; i < 3+this->NumberOfComponents; ++i)
1002       {
1003       v[i] = pt2[i] - pt1[i];
1004       }
1005 
1006     // equation for the edge pt1 + c * v
1007     // attempt least squares fit for c for A*(pt1 + c * v) = b
1008     // temp2 = A*v
1009     for (i = 0; i < 3 + this->NumberOfComponents; ++i)
1010       {
1011       temp2[i] = 0;
1012       for (j = 0; j < 3 + this->NumberOfComponents; ++j)
1013         {
1014         temp2[i] += this->TempA[i][j]*v[j];
1015         }
1016       }
1017 
1018     // c = v dot v
1019     for (i = 0; i <  3 + this->NumberOfComponents; ++i)
1020       {
1021       d += temp2[i]*temp2[i];
1022       }
1023 
1024     if ( d > errorNumber)
1025       {
1026       // temp = A*pt1
1027       for (i = 0; i < 3 + this->NumberOfComponents; ++i)
1028         {
1029         temp[i] = 0;
1030         for (j = 0; j < 3 + this->NumberOfComponents; ++j)
1031           {
1032           temp[i] += this->TempA[i][j]*pt1[j];
1033           }
1034         }
1035 
1036       for (i = 0; i < 3 + this->NumberOfComponents; i++)
1037         {
1038         temp[i] = this->TempB[i] - temp[i];
1039         }
1040 
1041       for (i = 0; i < 3 + this->NumberOfComponents; i++)
1042         {
1043         c += temp2[i]*temp[i];
1044         }
1045       c = c/d;
1046 
1047       for (i = 0; i < 3  + this->NumberOfComponents; i++)
1048         {
1049         x[i] = pt1[i]+c*v[i];
1050         }
1051       }
1052     else
1053       {
1054       // use mid point
1055       // might want to change to best of mid and end points??
1056       for (i = 0; i < 3  + this->NumberOfComponents; i++)
1057         {
1058         x[i] = 0.5*(pt1[i]+pt2[i]);
1059         }
1060       }
1061     delete[] pt1;
1062     delete[] pt2;
1063     delete[] v;
1064     delete[] temp;
1065     delete[] temp2;
1066     }
1067 
1068   // Compute the cost
1069   // x'*A*x - 2*b*x + d
1070   for (i = 0; i < 3+this->NumberOfComponents; i++)
1071     {
1072     cost += this->TempA[i][i]*x[i]*x[i];
1073     for (j = i+1; j < 3+this->NumberOfComponents; j++)
1074       {
1075       cost += 2.0*this->TempA[i][j]*x[i]*x[j];
1076       }
1077     }
1078   for (i = 0; i < 3+this->NumberOfComponents; i++)
1079     {
1080     cost -=  2.0 * this->TempB[i]*x[i];
1081     }
1082 
1083   cost += this->TempQuad[9];
1084 
1085   return cost;
1086 }
1087 
1088 
CollapseEdge(vtkIdType pt0Id,vtkIdType pt1Id)1089 int vtkQuadricDecimation::CollapseEdge(vtkIdType pt0Id, vtkIdType pt1Id)
1090 {
1091   int j, numDeleted=0;
1092   vtkIdType i, npts, *pts, cellId;
1093 
1094   this->Mesh->GetPointCells(pt0Id, this->CollapseCellIds);
1095   for (i = 0; i < this->CollapseCellIds->GetNumberOfIds(); i++)
1096     {
1097     cellId = this->CollapseCellIds->GetId(i);
1098     this->Mesh->GetCellPoints(cellId, npts, pts);
1099     for (j = 0; j < 3; j++)
1100       {
1101       if (pts[j] == pt1Id)
1102         {
1103         this->Mesh->RemoveCellReference(cellId);
1104         this->Mesh->DeleteCell(cellId);
1105         numDeleted++;
1106         }
1107       }
1108     }
1109 
1110   this->Mesh->GetPointCells(pt1Id, this->CollapseCellIds);
1111   this->Mesh->ResizeCellList(pt0Id, this->CollapseCellIds->GetNumberOfIds());
1112   for (i=0; i < this->CollapseCellIds->GetNumberOfIds(); i++)
1113     {
1114     cellId = this->CollapseCellIds->GetId(i);
1115     this->Mesh->GetCellPoints(cellId, npts, pts);
1116     // making sure we don't already have the triangle we're about to
1117     // change this one to
1118     if ((pts[0] == pt1Id && this->Mesh->IsTriangle(pt0Id, pts[1], pts[2])) ||
1119         (pts[1] == pt1Id && this->Mesh->IsTriangle(pts[0], pt0Id, pts[2])) ||
1120         (pts[2] == pt1Id && this->Mesh->IsTriangle(pts[0], pts[1], pt0Id)))
1121       {
1122       this->Mesh->RemoveCellReference(cellId);
1123       this->Mesh->DeleteCell(cellId);
1124       numDeleted++;
1125       }
1126     else
1127       {
1128       this->Mesh->AddReferenceToCell(pt0Id, cellId);
1129       this->Mesh->ReplaceCellPoint(cellId, pt1Id, pt0Id);
1130       }
1131     }
1132   this->Mesh->DeletePoint(pt1Id);
1133 
1134   return numDeleted;
1135 }
1136 
1137 
1138 // triangle t0, t1, t2 and point x
1139 // determins if t0 and x are on the same side of the plane defined by
1140 // t1 and t2, and parallel to the normal of the triangle
TrianglePlaneCheck(const double t0[3],const double t1[3],const double t2[3],const double * x)1141 int vtkQuadricDecimation::TrianglePlaneCheck(const double t0[3],
1142                                              const double t1[3],
1143                                              const double t2[3],
1144                                              const double *x) {
1145   double e0[3], e1[3], n[3], e2[3];
1146   double c;
1147   int i;
1148 
1149   for (i = 0; i < 3; i++)
1150     {
1151     e0[i] = t2[i] - t1[i];
1152     }
1153   for (i = 0; i < 3; i++)
1154     {
1155     e1[i] = t0[i] - t1[i];
1156     }
1157 
1158   // projection of e0 onto e1
1159   c = vtkMath::Dot(e0,e1)/(e0[0]*e0[0]+e0[1]*e0[1]+e0[2]*e0[2]);
1160   for (i = 0; i < 3; i++)
1161     {
1162     n[i] = e1[i] - c*e0[i];
1163     }
1164 
1165   for ( i = 0; i < 3; i++)
1166     {
1167     e2[i] = x[i] - t1[i];
1168     }
1169 
1170   vtkMath::Normalize(n);
1171   vtkMath::Normalize(e2);
1172   if (vtkMath::Dot(n, e2) > 1e-5)
1173     {
1174     return 1;
1175     }
1176   else
1177     {
1178     return 0;
1179     }
1180 }
1181 
IsGoodPlacement(vtkIdType pt0Id,vtkIdType pt1Id,const double * x)1182 int vtkQuadricDecimation::IsGoodPlacement(vtkIdType pt0Id, vtkIdType pt1Id,
1183 const double *x)
1184 {
1185   unsigned short ncells, i;
1186   vtkIdType npts, *pts,  ptId, *cells;
1187   double pt1[3], pt2[3], pt3[3];
1188 
1189   this->Mesh->GetPointCells(pt0Id, ncells, cells);
1190   for (i = 0; i < ncells; i++) {
1191   this->Mesh->GetCellPoints(cells[i], npts, pts);
1192   // assume triangle
1193   if (pts[0] != pt1Id && pts[1] != pt1Id && pts[2] != pt1Id)
1194     {
1195     for (ptId = 0; ptId < 3; ptId++)
1196       {
1197       if (pts[ptId] == pt0Id)
1198         {
1199         this->Mesh->GetPoint(pts[ptId], pt1);
1200         this->Mesh->GetPoint(pts[(ptId+1)%3], pt2);
1201         this->Mesh->GetPoint(pts[(ptId+2)%3], pt3);
1202         if(!this->TrianglePlaneCheck(pt1, pt2, pt3, x))
1203           {
1204           return 0;
1205           }
1206         }
1207       }
1208     }
1209   }
1210 
1211   this->Mesh->GetPointCells(pt1Id, ncells, cells);
1212   for (i = 0; i < ncells; i++)
1213     {
1214     this->Mesh->GetCellPoints(cells[i], npts, pts);
1215     // assume triangle
1216     if (pts[0] != pt0Id && pts[1] != pt0Id && pts[2] != pt0Id)
1217       {
1218       for (ptId = 0; ptId < 3; ptId++)
1219         {
1220         if (pts[ptId] == pt1Id)
1221           {
1222           this->Mesh->GetPoint(pts[ptId], pt1);
1223           this->Mesh->GetPoint(pts[(ptId+1)%3], pt2);
1224           this->Mesh->GetPoint(pts[(ptId+2)%3], pt3);
1225           if(!this->TrianglePlaneCheck(pt1, pt2, pt3, x))
1226             {
1227             return 0;
1228             }
1229           }
1230         }
1231       }
1232     }
1233 
1234   return 1;
1235 }
1236 
1237 
ComputeNumberOfComponents(void)1238 void vtkQuadricDecimation::ComputeNumberOfComponents(void)
1239 {
1240   vtkPointData *pd = this->Mesh->GetPointData();
1241   int i, j;
1242   double range[2], maxRange=0.0;
1243 
1244   this->NumberOfComponents = 0;
1245   pd->CopyAllOff();
1246 
1247   for (i = 0; i < 6; i++)
1248     {
1249     this->AttributeComponents[i] = 0;
1250     this->AttributeScale[i] = 1.0;
1251     }
1252 
1253   // Scalar attributes
1254   if (pd->GetScalars() != NULL && this->ScalarsAttribute)
1255     {
1256     for (j = 0; j < pd->GetScalars()->GetNumberOfComponents(); j++)
1257       {
1258       pd->GetScalars()->GetRange(range, j);
1259       maxRange = (maxRange < (range[1] - range[0]) ?
1260                   (range[1] - range[0]) : maxRange);
1261       }
1262     if (maxRange != 0.0)
1263       {
1264       this->NumberOfComponents +=  pd->GetScalars()->GetNumberOfComponents();
1265       pd->CopyScalarsOn();
1266       this->AttributeScale[0] = this->ScalarsWeight/maxRange;
1267       maxRange = 0.0;
1268       }
1269     vtkDebugMacro("scalars "<< this->NumberOfComponents << " "
1270                   << this->AttributeScale[0]);
1271     }
1272   this->AttributeComponents[0] = this->NumberOfComponents;
1273 
1274   // Vector attributes
1275   if (pd->GetVectors() != NULL && this->VectorsAttribute)
1276     {
1277     for (j = 0; j < pd->GetVectors()->GetNumberOfComponents(); j++)
1278       {
1279       pd->GetVectors()->GetRange(range, j);
1280       maxRange = (maxRange < (range[1] - range[0]) ?
1281                   (range[1] - range[0]) : maxRange);
1282       }
1283     if (maxRange != 0.0)
1284       {
1285       this->NumberOfComponents += pd->GetVectors()->GetNumberOfComponents();
1286       pd->CopyVectorsOn();
1287       this->AttributeScale[1] = this->VectorsWeight/maxRange;
1288       maxRange = 0.0;
1289       }
1290     vtkDebugMacro("vectors "<< this->NumberOfComponents << " "
1291                   << this->AttributeScale[1]);
1292     }
1293   this->AttributeComponents[1] = this->NumberOfComponents;
1294 
1295   // Normals attributes -- normals are assumed normalized
1296   if (pd->GetNormals() != NULL && this->NormalsAttribute)
1297     {
1298     this->NumberOfComponents += 3;
1299     pd->CopyNormalsOn();
1300     this->AttributeScale[2] = 0.5*this->NormalsWeight;
1301     vtkDebugMacro("normals "<< this->NumberOfComponents << " "
1302                   << this->AttributeScale[2]);
1303     }
1304   this->AttributeComponents[2] = this->NumberOfComponents;
1305 
1306   // Texture coords attributes
1307   if (pd->GetTCoords() != NULL && this->TCoordsAttribute)
1308     {
1309     for (j = 0; j < pd->GetTCoords()->GetNumberOfComponents(); j++)
1310       {
1311       pd->GetTCoords()->GetRange(range, j);
1312       maxRange = (maxRange < (range[1] - range[0]) ?
1313                   (range[1] - range[0]) : maxRange);
1314       }
1315     if (maxRange != 0.0)
1316       {
1317       this->NumberOfComponents += pd->GetTCoords()->GetNumberOfComponents();
1318       pd->CopyTCoordsOn();
1319       this->AttributeScale[3] = this->TCoordsWeight/maxRange;
1320       maxRange = 0.0;
1321       }
1322     vtkDebugMacro("tcoords "<< this->NumberOfComponents << " "
1323                   << this->AttributeScale[3]);
1324     }
1325   this->AttributeComponents[3] = this->NumberOfComponents;
1326 
1327   // Tensors attributes
1328   if (pd->GetTensors() != NULL && this->TensorsAttribute)
1329     {
1330     for (j = 0; j < 9; j++)
1331       {
1332       pd->GetTensors()->GetRange(range, j);
1333       maxRange = (maxRange < (range[1] - range[0]) ?
1334                   (range[1] - range[0]) : maxRange);
1335       }
1336     if (maxRange != 0.0)
1337       {
1338       this->NumberOfComponents += 9;
1339       pd->CopyTensorsOn();
1340       this->AttributeScale[4] = this->TensorsWeight/maxRange;
1341       }
1342     vtkDebugMacro("tensors "<< this->NumberOfComponents << " "
1343                   << this->AttributeScale[4]);
1344     }
1345   this->AttributeComponents[4] = this->NumberOfComponents;
1346 
1347   vtkDebugMacro("Number of components: " << this->NumberOfComponents);
1348 }
1349 
1350 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)1351 void vtkQuadricDecimation::PrintSelf(ostream& os, vtkIndent indent)
1352 {
1353   this->Superclass::PrintSelf(os,indent);
1354 
1355   os << indent << "Target Reduction: " << this->TargetReduction << "\n";
1356   os << indent << "Actual Reduction: " << this->ActualReduction << "\n";
1357 
1358   os << indent << "Attribute Error Metric: "
1359      << (this->AttributeErrorMetric ? "On\n" : "Off\n");
1360   os << indent << "Scalars Attribute: "
1361      << (this->ScalarsAttribute ? "On\n" : "Off\n");
1362   os << indent << "Vectors Attribute: "
1363      << (this->VectorsAttribute ? "On\n" : "Off\n");
1364   os << indent << "Normals Attribute: "
1365      << (this->NormalsAttribute ? "On\n" : "Off\n");
1366   os << indent << "TCoords Attribute: "
1367      << (this->TCoordsAttribute ? "On\n" : "Off\n");
1368   os << indent << "Tensors Attribute: "
1369      << (this->TensorsAttribute ? "On\n" : "Off\n");
1370 
1371   os << indent << "Scalars Weight: " << this->ScalarsWeight << "\n";
1372   os << indent << "Vectors Weight: " << this->VectorsWeight << "\n";
1373   os << indent << "Normals Weight: " << this->NormalsWeight << "\n";
1374   os << indent << "TCoords Weight: " << this->TCoordsWeight << "\n";
1375   os << indent << "Tensors Weight: " << this->TensorsWeight << "\n";
1376 }
1377