1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkClipClosedSurface.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 "vtkClipClosedSurface.h"
16 
17 #include "vtkDataSet.h"
18 #include "vtkInformation.h"
19 #include "vtkInformationVector.h"
20 #include "vtkObjectFactory.h"
21 #include "vtkImageData.h"
22 #include "vtkPolyData.h"
23 #include "vtkPoints.h"
24 #include "vtkCellArray.h"
25 #include "vtkCellData.h"
26 #include "vtkPointData.h"
27 #include "vtkUnsignedCharArray.h"
28 #include "vtkSignedCharArray.h"
29 #include "vtkDoubleArray.h"
30 #include "vtkPlaneCollection.h"
31 #include "vtkMath.h"
32 #include "vtkPolygon.h"
33 #include "vtkTriangleStrip.h"
34 #include "vtkLine.h"
35 #include "vtkMatrix4x4.h"
36 #include "vtkContourTriangulator.h"
37 
38 #include "vtkIncrementalOctreePointLocator.h"
39 
40 #include <vector>
41 #include <algorithm>
42 #include <map>
43 #include <utility>
44 
45 vtkStandardNewMacro(vtkClipClosedSurface);
46 
47 vtkCxxSetObjectMacro(vtkClipClosedSurface,ClippingPlanes,vtkPlaneCollection);
48 
49 //----------------------------------------------------------------------------
vtkClipClosedSurface()50 vtkClipClosedSurface::vtkClipClosedSurface()
51 {
52   this->ClippingPlanes = nullptr;
53   this->Tolerance = 1e-6;
54   this->PassPointData = 0;
55 
56   this->ScalarMode = VTK_CCS_SCALAR_MODE_NONE;
57   this->GenerateOutline = 0;
58   this->GenerateFaces = 1;
59   this->ActivePlaneId = -1;
60 
61   this->BaseColor[0] = 1.0;
62   this->BaseColor[1] = 0.0;
63   this->BaseColor[2] = 0.0;
64 
65   this->ClipColor[0] = 1.0;
66   this->ClipColor[1] = 0.5;
67   this->ClipColor[2] = 0.0;
68 
69   this->ActivePlaneColor[0] = 1.0;
70   this->ActivePlaneColor[1] = 1.0;
71   this->ActivePlaneColor[2] = 0.0;
72 
73   this->TriangulationErrorDisplay = 0;
74 
75   // A whole bunch of objects needed during execution
76   this->IdList = nullptr;
77 }
78 
79 //----------------------------------------------------------------------------
~vtkClipClosedSurface()80 vtkClipClosedSurface::~vtkClipClosedSurface()
81 {
82   if (this->ClippingPlanes) { this->ClippingPlanes->Delete(); }
83 
84   if (this->IdList) { this->IdList->Delete(); }
85 }
86 
87 //----------------------------------------------------------------------------
GetScalarModeAsString()88 const char *vtkClipClosedSurface::GetScalarModeAsString()
89 {
90   switch (this->ScalarMode)
91   {
92     case VTK_CCS_SCALAR_MODE_NONE:
93       return "None";
94     case VTK_CCS_SCALAR_MODE_COLORS:
95       return "Colors";
96     case VTK_CCS_SCALAR_MODE_LABELS:
97       return "Labels";
98   }
99   return "";
100 }
101 
102 //----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)103 void vtkClipClosedSurface::PrintSelf(ostream& os, vtkIndent indent)
104 {
105   this->Superclass::PrintSelf(os,indent);
106 
107   os << indent << "ClippingPlanes: ";
108   if (this->ClippingPlanes)
109   {
110     os << this->ClippingPlanes << "\n";
111   }
112   else
113   {
114     os << "(none)\n";
115   }
116 
117   os << indent << "Tolerance: " << this->Tolerance << "\n";
118 
119   os << indent << "PassPointData: "
120      << (this->PassPointData ? "On\n" : "Off\n" );
121 
122   os << indent << "GenerateOutline: "
123      << (this->GenerateOutline ? "On\n" : "Off\n" );
124 
125   os << indent << "GenerateFaces: "
126      << (this->GenerateFaces ? "On\n" : "Off\n" );
127 
128   os << indent << "ScalarMode: "
129      << this->GetScalarModeAsString() << "\n";
130 
131   os << indent << "BaseColor: " << this->BaseColor[0] << ", "
132      << this->BaseColor[1] << ", " << this->BaseColor[2] << "\n";
133 
134   os << indent << "ClipColor: " << this->ClipColor[0] << ", "
135      << this->ClipColor[1] << ", " << this->ClipColor[2] << "\n";
136 
137   os << indent << "ActivePlaneId: " << this->ActivePlaneId << "\n";
138 
139   os << indent << "ActivePlaneColor: " << this->ActivePlaneColor[0] << ", "
140      << this->ActivePlaneColor[1] << ", " << this->ActivePlaneColor[2] << "\n";
141 
142   os << indent << "TriangulationErrorDisplay: "
143      << (this->TriangulationErrorDisplay ? "On\n" : "Off\n" );
144 }
145 
146 //----------------------------------------------------------------------------
ComputePipelineMTime(vtkInformation * vtkNotUsed (request),vtkInformationVector ** vtkNotUsed (inputVector),vtkInformationVector * vtkNotUsed (outputVector),int vtkNotUsed (requestFromOutputPort),vtkMTimeType * mtime)147 int vtkClipClosedSurface::ComputePipelineMTime(
148   vtkInformation* vtkNotUsed(request),
149   vtkInformationVector** vtkNotUsed(inputVector),
150   vtkInformationVector* vtkNotUsed(outputVector),
151   int vtkNotUsed(requestFromOutputPort),
152   vtkMTimeType* mtime)
153 {
154   vtkMTimeType mTime = this->GetMTime();
155 
156   vtkPlaneCollection *planes = this->ClippingPlanes;
157   vtkPlane *plane = nullptr;
158 
159   if (planes)
160   {
161     vtkMTimeType planesMTime = planes->GetMTime();
162     if (planesMTime > mTime)
163     {
164       mTime = planesMTime;
165     }
166 
167     vtkCollectionSimpleIterator iter;
168     planes->InitTraversal(iter);
169     while ( (plane = planes->GetNextPlane(iter)) )
170     {
171       vtkMTimeType planeMTime = plane->GetMTime();
172       if (planeMTime > mTime)
173       {
174         mTime = planeMTime;
175       }
176     }
177   }
178 
179   *mtime = mTime;
180 
181   return 1;
182 }
183 
184 //----------------------------------------------------------------------------
185 // A helper class to quickly locate an edge, given the endpoint ids.
186 // It uses an stl map rather than a table partitioning scheme, since
187 // we have no idea how many entries there will be when we start.  So
188 // the performance is approximately log(n).
189 
190 class vtkCCSEdgeLocatorNode
191 {
192 public:
vtkCCSEdgeLocatorNode()193   vtkCCSEdgeLocatorNode() :
194     ptId0(-1), ptId1(-1), edgeId(-1), next(nullptr) {};
195 
FreeList()196   void FreeList() {
197     vtkCCSEdgeLocatorNode *ptr = this->next;
198     while (ptr)
199     {
200       vtkCCSEdgeLocatorNode *tmp = ptr;
201       ptr = ptr->next;
202       tmp->next = nullptr;
203       delete tmp;
204     }
205   };
206 
207   vtkIdType ptId0;
208   vtkIdType ptId1;
209   vtkIdType edgeId;
210   vtkCCSEdgeLocatorNode *next;
211 };
212 
213 
214 class vtkCCSEdgeLocator
215 {
216 private:
217   typedef std::map<vtkIdType, vtkCCSEdgeLocatorNode> MapType;
218   MapType EdgeMap;
219 
220 public:
New()221   static vtkCCSEdgeLocator *New() {
222     return new vtkCCSEdgeLocator; };
223 
Delete()224   void Delete() {
225     this->Initialize();
226     delete this; };
227 
228   // Description:
229   // Initialize the locator.
230   void Initialize();
231 
232   // Description:
233   // If edge (i0, i1) is not in the list, then it will be added and
234   // a pointer for storing the new edgeId will be returned.
235   // If edge (i0, i1) is in the list, then edgeId will be set to the
236   // stored value and a null pointer will be returned.
237   vtkIdType *InsertUniqueEdge(vtkIdType i0, vtkIdType i1, vtkIdType &edgeId);
238 };
239 
Initialize()240 void vtkCCSEdgeLocator::Initialize()
241 {
242   for (MapType::iterator i = this->EdgeMap.begin();
243        i != this->EdgeMap.end();
244        ++i)
245   {
246     i->second.FreeList();
247   }
248   this->EdgeMap.clear();
249 }
250 
InsertUniqueEdge(vtkIdType i0,vtkIdType i1,vtkIdType & edgeId)251 vtkIdType *vtkCCSEdgeLocator::InsertUniqueEdge(
252   vtkIdType i0, vtkIdType i1, vtkIdType &edgeId)
253 {
254   // Ensure consistent ordering of edge
255   if (i1 < i0)
256   {
257     vtkIdType tmp = i0;
258     i0 = i1;
259     i1 = tmp;
260   }
261 
262   // Generate a integer key, try to make it unique
263 #ifdef VTK_USE_64BIT_IDS
264   vtkIdType key = ((i1 << 32) ^ i0);
265 #else
266   vtkIdType key = ((i1 << 16) ^ i0);
267 #endif
268 
269   vtkCCSEdgeLocatorNode *node = &this->EdgeMap[key];
270 
271   if (node->ptId1 < 0)
272   {
273     // Didn't find key, so add a new edge entry
274     node->ptId0 = i0;
275     node->ptId1 = i1;
276     return &node->edgeId;
277   }
278 
279   // Search through the list for i0 and i1
280   if (node->ptId0 == i0 && node->ptId1 == i1)
281   {
282     edgeId = node->edgeId;
283     return nullptr;
284   }
285 
286   int i = 1;
287   while (node->next != nullptr)
288   {
289     i++;
290     node = node->next;
291 
292     if (node->ptId0 == i0 && node->ptId1 == i1)
293     {
294       edgeId = node->edgeId;
295       return nullptr;
296     }
297   }
298 
299   // No entry for i1, so make one and return
300   node->next = new vtkCCSEdgeLocatorNode;
301   node = node->next;
302   node->ptId0 = i0;
303   node->ptId1 = i1;
304   node->edgeId = static_cast<vtkIdType>(this->EdgeMap.size()-1);
305   return &node->edgeId;
306 }
307 
308 //----------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)309 int vtkClipClosedSurface::RequestData(
310   vtkInformation *vtkNotUsed(request),
311   vtkInformationVector **inputVector,
312   vtkInformationVector *outputVector)
313 {
314   // Get the info objects
315   vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
316   vtkInformation *outInfo = outputVector->GetInformationObject(0);
317 
318   // Get the input and output
319   vtkPolyData *input = vtkPolyData::SafeDownCast(
320     inInfo->Get(vtkDataObject::DATA_OBJECT()));
321   vtkPolyData *output = vtkPolyData::SafeDownCast(
322     outInfo->Get(vtkDataObject::DATA_OBJECT()));
323 
324   // Create objects needed for temporary storage
325   if (this->IdList == nullptr) { this->IdList = vtkIdList::New(); }
326 
327   // Get the input points
328   vtkPoints *inputPoints = input->GetPoints();
329   vtkIdType numPts = 0;
330   int inputPointsType = VTK_FLOAT;
331   if (inputPoints)
332   {
333     numPts = inputPoints->GetNumberOfPoints();
334     inputPointsType = inputPoints->GetDataType();
335   }
336 
337   // Force points to double precision, copy the point attributes
338   vtkPoints *points = vtkPoints::New();
339   points->SetDataTypeToDouble();
340   points->SetNumberOfPoints(numPts);
341 
342   vtkPointData *pointData = vtkPointData::New();
343   vtkPointData *inPointData = nullptr;
344 
345   if (this->PassPointData)
346   {
347     inPointData = input->GetPointData();
348     pointData->InterpolateAllocate(inPointData, numPts, 0);
349   }
350 
351   for (vtkIdType ptId = 0; ptId < numPts; ptId++)
352   {
353     double point[3];
354     inputPoints->GetPoint(ptId, point);
355     points->SetPoint(ptId, point);
356     // Point data is not copied from input
357     if (inPointData)
358     {
359       pointData->CopyData(inPointData, ptId, ptId);
360     }
361   }
362 
363   // An edge locator to avoid point duplication while clipping
364   vtkCCSEdgeLocator *edgeLocator = vtkCCSEdgeLocator::New();
365 
366   // A temporary polydata for the contour lines that are triangulated
367   vtkPolyData *tmpContourData = vtkPolyData::New();
368 
369   // The cell scalars
370   vtkUnsignedCharArray *lineScalars = nullptr;
371   vtkUnsignedCharArray *polyScalars = nullptr;
372   vtkUnsignedCharArray *inputScalars = nullptr;
373 
374   // For input scalars: the offsets to the various cell types
375   vtkIdType firstLineScalar = 0;
376   vtkIdType firstPolyScalar = 0;
377   vtkIdType firstStripScalar = 0;
378 
379   // Make the colors to be used on the data.
380   int numberOfScalarComponents = 1;
381   unsigned char colors[3][3];
382 
383   if (this->ScalarMode == VTK_CCS_SCALAR_MODE_COLORS)
384   {
385     numberOfScalarComponents = 3;
386     this->CreateColorValues(this->BaseColor, this->ClipColor,
387                             this->ActivePlaneColor, colors);
388   }
389   else if (this->ScalarMode == VTK_CCS_SCALAR_MODE_LABELS)
390   {
391     colors[0][0] = 0;
392     colors[1][0] = 1;
393     colors[2][0] = 2;
394   }
395 
396   // This is set if we have to work with scalars.  The input scalars
397   // will be copied if they are unsigned char with 3 components, otherwise
398   // new scalars will be generated.
399   if (this->ScalarMode)
400   {
401     // Make the scalars
402     lineScalars = vtkUnsignedCharArray::New();
403     lineScalars->SetNumberOfComponents(numberOfScalarComponents);
404 
405     vtkDataArray *tryInputScalars = input->GetCellData()->GetScalars();
406     // Get input scalars if they are RGB color scalars
407     if (tryInputScalars && tryInputScalars->IsA("vtkUnsignedCharArray") &&
408         numberOfScalarComponents == 3 &&
409         tryInputScalars->GetNumberOfComponents() == 3)
410     {
411       inputScalars = static_cast<vtkUnsignedCharArray *>(
412         input->GetCellData()->GetScalars());
413 
414       vtkIdType numVerts = 0;
415       vtkIdType numLines = 0;
416       vtkIdType numPolys = 0;
417       vtkCellArray *tmpCellArray = nullptr;
418       if ( (tmpCellArray = input->GetVerts()) )
419       {
420         numVerts = tmpCellArray->GetNumberOfCells();
421       }
422       if ( (tmpCellArray = input->GetLines()) )
423       {
424         numLines = tmpCellArray->GetNumberOfCells();
425       }
426       if ( (tmpCellArray = input->GetPolys()) )
427       {
428         numPolys = tmpCellArray->GetNumberOfCells();
429       }
430       firstLineScalar = numVerts;
431       firstPolyScalar = numVerts + numLines;
432       firstStripScalar = numVerts + numLines + numPolys;
433     }
434   }
435 
436   // Break the input lines into segments, generate scalars for lines
437   vtkCellArray *lines = vtkCellArray::New();
438   if (input->GetLines() && input->GetLines()->GetNumberOfCells() > 0)
439   {
440     this->BreakPolylines(input->GetLines(), lines, inputScalars,
441                          firstLineScalar, lineScalars, colors[0]);
442   }
443 
444   // Copy the polygons, convert strips to triangles
445   vtkCellArray *polys = nullptr;
446   int polyMax = 3;
447   if ((input->GetPolys() && input->GetPolys()->GetNumberOfCells() > 0) ||
448       (input->GetStrips() && input->GetStrips()->GetNumberOfCells() > 0))
449   {
450     // If there are line scalars, then poly scalars are needed too
451     if (lineScalars)
452     {
453       polyScalars = vtkUnsignedCharArray::New();
454       polyScalars->SetNumberOfComponents(numberOfScalarComponents);
455     }
456 
457     polys = vtkCellArray::New();
458     this->CopyPolygons(input->GetPolys(), polys, inputScalars,
459                        firstPolyScalar, polyScalars, colors[0]);
460     this->BreakTriangleStrips(input->GetStrips(), polys, inputScalars,
461                               firstStripScalar, polyScalars, colors[0]);
462 
463     // Check if the input has polys and quads or just triangles
464     vtkIdType npts = 0;
465     vtkIdType *pts = nullptr;
466     vtkCellArray *inPolys = input->GetPolys();
467     inPolys->InitTraversal();
468     while (inPolys->GetNextCell(npts, pts))
469     {
470       if (npts > polyMax)
471       {
472         polyMax = npts;
473       }
474     }
475   }
476 
477   // Get the clipping planes
478   vtkPlaneCollection *planes = this->ClippingPlanes;
479 
480   // Arrays for storing the clipped lines and polys.
481   vtkCellArray *newLines = vtkCellArray::New();
482   vtkCellArray *newPolys = nullptr;
483   if (polys)
484   {
485     newPolys = vtkCellArray::New();
486   }
487 
488   // The point scalars, needed for clipping (not for the output!)
489   vtkDoubleArray *pointScalars = vtkDoubleArray::New();
490 
491   // The line scalars, for coloring the outline
492   vtkCellData *inLineData = vtkCellData::New();
493   inLineData->CopyScalarsOn();
494   inLineData->SetScalars(lineScalars);
495   if (lineScalars)
496   {
497     lineScalars->Delete();
498     lineScalars = nullptr;
499   }
500 
501   // The poly scalars, for coloring the faces
502   vtkCellData *inPolyData = vtkCellData::New();
503   inPolyData->CopyScalarsOn();
504   inPolyData->SetScalars(polyScalars);
505   if (polyScalars)
506   {
507     polyScalars->Delete();
508     polyScalars = nullptr;
509   }
510 
511   // Also create output attribute data
512   vtkCellData *outLineData = vtkCellData::New();
513   outLineData->CopyScalarsOn();
514 
515   vtkCellData *outPolyData = vtkCellData::New();
516   outPolyData->CopyScalarsOn();
517 
518   // Go through the clipping planes and clip the input with each plane
519   vtkCollectionSimpleIterator iter;
520   int numPlanes = 0;
521   if (planes)
522   {
523     planes->InitTraversal(iter);
524     numPlanes = planes->GetNumberOfItems();
525   }
526 
527   vtkPlane *plane = nullptr;
528   for (int planeId = 0;
529        planes && (plane = planes->GetNextPlane(iter));
530        planeId++)
531   {
532     this->UpdateProgress((planeId + 1.0)/(numPlanes + 1.0));
533     if (this->GetAbortExecute())
534     {
535       break;
536     }
537 
538     // Is this the last cut plane?  If so, generate triangles.
539     int triangulate = 5;
540     if (planeId == numPlanes-1)
541     {
542       triangulate = polyMax;
543     }
544 
545     // Is this the active plane?
546     int active = (planeId == this->ActivePlaneId);
547 
548     // Convert the plane into an easy-to-evaluate function
549     double pc[4];
550     plane->GetNormal(pc);
551     pc[3] = -vtkMath::Dot(pc, plane->GetOrigin());
552 
553     // Create the clip scalars by evaluating the plane at each point
554     vtkIdType numPoints = points->GetNumberOfPoints();
555     pointScalars->SetNumberOfValues(numPoints);
556     for (vtkIdType pointId = 0; pointId < numPoints; pointId++)
557     {
558       double p[3];
559       points->GetPoint(pointId, p);
560       double val = p[0]*pc[0] + p[1]*pc[1] + p[2]*pc[2] + pc[3];
561       pointScalars->SetValue(pointId, val);
562     }
563 
564     // Prepare the output scalars
565     outLineData->CopyAllocate(inLineData, 0, 0);
566     outPolyData->CopyAllocate(inPolyData, 0, 0);
567 
568     // Reset the locator
569     edgeLocator->Initialize();
570 
571     // Clip the lines
572     this->ClipLines(points, pointScalars, pointData, edgeLocator,
573                     lines, newLines, inLineData, outLineData);
574 
575     // Clip the polys
576     if (polys)
577     {
578       // Get the number of lines remaining after the clipping
579       vtkIdType numClipLines = newLines->GetNumberOfCells();
580 
581       // Cut the polys to generate more lines
582       this->ClipAndContourPolys(points, pointScalars, pointData, edgeLocator,
583                                 triangulate, polys, newPolys, newLines,
584                                 inPolyData, outPolyData, outLineData);
585 
586       // Add scalars for the newly-created contour lines
587       vtkUnsignedCharArray *scalars =
588         vtkArrayDownCast<vtkUnsignedCharArray>(outLineData->GetScalars());
589 
590       if (scalars)
591       {
592         // Set the color to the active color if plane is active
593         unsigned char *color = colors[1+active];
594         unsigned char *activeColor = colors[2];
595 
596         vtkIdType numLines = newLines->GetNumberOfCells();
597         for (vtkIdType lineId = numClipLines; lineId < numLines; lineId++)
598         {
599           unsigned char oldColor[3];
600           scalars->GetTypedTuple(lineId, oldColor);
601           if (numberOfScalarComponents != 3 ||
602               oldColor[0] != activeColor[0] ||
603               oldColor[1] != activeColor[1] ||
604               oldColor[2] != activeColor[2])
605           {
606             scalars->SetTypedTuple(lineId, color);
607           }
608         }
609       }
610 
611       // Generate new polys from the cut lines
612       vtkIdType cellId = newPolys->GetNumberOfCells();
613       vtkIdType numClipAndContourLines = newLines->GetNumberOfCells();
614 
615       // Create a polydata for the lines
616       tmpContourData->SetPoints(points);
617       tmpContourData->SetLines(newLines);
618       tmpContourData->BuildCells();
619 
620       this->TriangulateContours(tmpContourData, numClipLines,
621                                   numClipAndContourLines - numClipLines,
622                                   newPolys, pc);
623 
624       // Add scalars for the newly-created polys
625       scalars = vtkArrayDownCast<vtkUnsignedCharArray>(outPolyData->GetScalars());
626 
627       if (scalars)
628       {
629         unsigned char *color = colors[1+active];
630 
631         vtkIdType numCells = newPolys->GetNumberOfCells();
632         if (numCells > cellId)
633         {
634           // The insert allocates space up to numCells-1
635           scalars->InsertTypedTuple(numCells-1, color);
636           for (;cellId < numCells; cellId++)
637           {
638             scalars->SetTypedTuple(cellId, color);
639           }
640         }
641       }
642 
643       // Add scalars to any diagnostic lines that added by
644       // TriangulateContours().  In usual operation, no lines are added.
645       scalars = vtkArrayDownCast<vtkUnsignedCharArray>(outLineData->GetScalars());
646 
647       if (scalars)
648       {
649         unsigned char color[3] = { 0, 255, 255 };
650 
651         vtkIdType numCells = newLines->GetNumberOfCells();
652         if (numCells > numClipAndContourLines)
653         {
654           // The insert allocates space up to numCells-1
655           scalars->InsertTypedTuple(numCells-1, color);
656           for (vtkIdType lineCellId = numClipAndContourLines;
657                lineCellId < numCells; lineCellId++)
658           {
659             scalars->SetTypedTuple(lineCellId, color);
660           }
661         }
662       }
663     }
664 
665     // Swap the lines, points, etcetera: old output becomes new input
666     vtkCellArray *tmp1 = lines;
667     lines = newLines;
668     newLines = tmp1;
669     newLines->Initialize();
670 
671     if (polys)
672     {
673       vtkCellArray *tmp2 = polys;
674       polys = newPolys;
675       newPolys = tmp2;
676       newPolys->Initialize();
677     }
678 
679     vtkCellData *tmp4 = inLineData;
680     inLineData = outLineData;
681     outLineData = tmp4;
682     outLineData->Initialize();
683 
684     vtkCellData *tmp5 = inPolyData;
685     inPolyData = outPolyData;
686     outPolyData = tmp5;
687     outPolyData->Initialize();
688   }
689 
690   // Delete the locator
691   edgeLocator->Delete();
692 
693   // Delete the contour data container
694   tmpContourData->Delete();
695 
696   // Delete the clip scalars
697   pointScalars->Delete();
698 
699   // Get the line scalars
700   vtkUnsignedCharArray *scalars =
701     vtkArrayDownCast<vtkUnsignedCharArray>(inLineData->GetScalars());
702 
703   if (this->GenerateOutline)
704   {
705     output->SetLines(lines);
706   }
707   else if (scalars)
708   {
709     // If not adding lines to output, clear the line scalars
710     scalars->Initialize();
711   }
712 
713   if (this->GenerateFaces)
714   {
715     output->SetPolys(polys);
716 
717     if (polys && scalars)
718     {
719       vtkUnsignedCharArray *pScalars =
720         vtkArrayDownCast<vtkUnsignedCharArray>(inPolyData->GetScalars());
721 
722       vtkIdType m = scalars->GetNumberOfTuples();
723       vtkIdType n = pScalars->GetNumberOfTuples();
724 
725       if (n > 0)
726       {
727         unsigned char color[3];
728         color[0] = color[1] = color[2] = 0;
729 
730         // This is just to expand the array
731         scalars->InsertTypedTuple(n+m-1, color);
732 
733         // Fill in the poly scalars
734         for (vtkIdType i = 0; i < n; i++)
735         {
736           pScalars->GetTypedTuple(i, color);
737           scalars->SetTypedTuple(i+m, color);
738         }
739       }
740     }
741   }
742 
743   lines->Delete();
744 
745   if (polys)
746   {
747     polys->Delete();
748   }
749 
750   if (this->ScalarMode == VTK_CCS_SCALAR_MODE_COLORS)
751   {
752     scalars->SetName("Colors");
753     output->GetCellData()->SetScalars(scalars);
754   }
755   else if (this->ScalarMode == VTK_CCS_SCALAR_MODE_LABELS)
756   {
757     // Don't use VTK_UNSIGNED_CHAR or they will look like color scalars
758     vtkSignedCharArray *categories = vtkSignedCharArray::New();
759     categories->DeepCopy(scalars);
760     categories->SetName("Labels");
761     output->GetCellData()->SetScalars(categories);
762     categories->Delete();
763   }
764   else
765   {
766     output->GetCellData()->SetScalars(nullptr);
767   }
768 
769   newLines->Delete();
770   if (newPolys)
771   {
772     newPolys->Delete();
773   }
774 
775   inLineData->Delete();
776   outLineData->Delete();
777   inPolyData->Delete();
778   outPolyData->Delete();
779 
780   // Finally, store the points in the output
781   this->SqueezeOutputPoints(output, points, pointData, inputPointsType);
782   output->Squeeze();
783 
784   points->Delete();
785   pointData->Delete();
786 
787   return 1;
788 }
789 
790 //----------------------------------------------------------------------------
SqueezeOutputPoints(vtkPolyData * output,vtkPoints * points,vtkPointData * pointData,int outputPointDataType)791 void vtkClipClosedSurface::SqueezeOutputPoints(
792     vtkPolyData *output, vtkPoints *points, vtkPointData *pointData,
793     int outputPointDataType)
794 {
795   // Create a list of points used by cells
796   vtkIdType n = points->GetNumberOfPoints();
797   vtkIdType numNewPoints = 0;
798 
799   // The point data
800   vtkPointData *outPointData = output->GetPointData();
801 
802   // A mapping from old pointIds to new pointIds
803   vtkIdType *pointMap = new vtkIdType[n];
804   for (vtkIdType i = 0; i < n; i++)
805   {
806     pointMap[i] = -1;
807   }
808 
809   vtkIdType npts, *pts;
810   vtkCellArray *cellArrays[4];
811   cellArrays[0] = output->GetVerts();
812   cellArrays[1] = output->GetLines();
813   cellArrays[2] = output->GetPolys();
814   cellArrays[3] = output->GetStrips();
815   int arrayId;
816 
817   // Find all the newPoints that are used by cells
818   for (arrayId = 0; arrayId < 4; arrayId++)
819   {
820     vtkCellArray *cellArray = cellArrays[arrayId];
821     if (cellArray)
822     {
823       cellArray->InitTraversal();
824       while (cellArray->GetNextCell(npts, pts))
825       {
826         for (vtkIdType ii = 0; ii < npts; ii++)
827         {
828           vtkIdType pointId = pts[ii];
829           if (pointMap[pointId] < 0)
830           {
831             pointMap[pointId] = numNewPoints++;
832           }
833         }
834       }
835     }
836   }
837 
838   // Create exactly the number of points that are required
839   vtkPoints *newPoints = vtkPoints::New();
840   newPoints->SetDataType(outputPointDataType);
841   newPoints->SetNumberOfPoints(numNewPoints);
842   outPointData->CopyAllocate(pointData, numNewPoints, 0);
843 
844   for (vtkIdType pointId = 0; pointId < n; pointId++)
845   {
846     vtkIdType newPointId = pointMap[pointId];
847     if (newPointId >= 0)
848     {
849       double p[3];
850       points->GetPoint(pointId, p);
851       newPoints->SetPoint(newPointId, p);
852       outPointData->CopyData(pointData, pointId, newPointId);
853     }
854   }
855 
856   // Change the cell pointIds to reflect the new point array
857   for (arrayId = 0; arrayId < 4; arrayId++)
858   {
859     vtkCellArray *cellArray = cellArrays[arrayId];
860     if (cellArray)
861     {
862       cellArray->InitTraversal();
863       while (cellArray->GetNextCell(npts, pts))
864       {
865         for (vtkIdType ii = 0; ii < npts; ii++)
866         {
867           vtkIdType pointId = pts[ii];
868           pts[ii] = pointMap[pointId];
869         }
870       }
871     }
872   }
873 
874   output->SetPoints(newPoints);
875   newPoints->Delete();
876 
877   delete [] pointMap;
878 }
879 
880 //----------------------------------------------------------------------------
CreateColorValues(const double color1[3],const double color2[3],const double color3[3],unsigned char colors[3][3])881 void vtkClipClosedSurface::CreateColorValues(
882   const double color1[3], const double color2[3], const double color3[3],
883   unsigned char colors[3][3])
884 {
885   // Convert colors from "double" to "unsigned char"
886 
887   const double *dcolors[3];
888   dcolors[0] = color1;
889   dcolors[1] = color2;
890   dcolors[2] = color3;
891 
892   for (int i = 0; i < 3; i++)
893   {
894     for (int j = 0; j < 3; j++)
895     {
896       double val = dcolors[i][j];
897       if (val < 0) { val = 0; }
898       if (val > 1) { val = 1; }
899       colors[i][j] = static_cast<unsigned char>(val*255);
900     }
901   }
902 }
903 
904 //----------------------------------------------------------------------------
905 // Point interpolation for clipping and contouring, given the scalar
906 // values (v0, v1) for the two endpoints (p0, p1).  The use of this
907 // function guarantees perfect consistency in the results.
InterpolateEdge(vtkPoints * points,vtkPointData * pointData,vtkCCSEdgeLocator * locator,double tol,vtkIdType i0,vtkIdType i1,double v0,double v1,vtkIdType & i)908 int vtkClipClosedSurface::InterpolateEdge(
909   vtkPoints *points, vtkPointData *pointData, vtkCCSEdgeLocator *locator,
910   double tol, vtkIdType i0, vtkIdType i1, double v0, double v1,
911   vtkIdType &i)
912 {
913   // This swap guarantees that exactly the same point is computed
914   // for both line directions, as long as the endpoints are the same.
915   if (v1 > 0)
916   {
917     vtkIdType tmpi = i0;
918     i0 = i1;
919     i1 = tmpi;
920 
921     double tmp = v0;
922     v0 = v1;
923     v1 = tmp;
924   }
925 
926   // After the above swap, i0 will be kept, and i1 will be clipped
927 
928   // Check to see if this point has already been computed
929   vtkIdType *iptr = locator->InsertUniqueEdge(i0, i1, i);
930   if (iptr == nullptr)
931   {
932     return 0;
933   }
934 
935   // Get the edge and interpolate the new point
936   double p0[3], p1[3], p[3];
937   points->GetPoint(i0, p0);
938   points->GetPoint(i1, p1);
939 
940   double f = v0/(v0 - v1);
941   double s = 1.0 - f;
942   double t = 1.0 - s;
943 
944   p[0] = s*p0[0] + t*p1[0];
945   p[1] = s*p0[1] + t*p1[1];
946   p[2] = s*p0[2] + t*p1[2];
947 
948   double tol2 = tol*tol;
949 
950   // Make sure that new point is far enough from kept point
951   if (vtkMath::Distance2BetweenPoints(p, p0) < tol2)
952   {
953     i = i0;
954     *iptr = i0;
955     return 0;
956   }
957 
958   if (vtkMath::Distance2BetweenPoints(p, p1) < tol2)
959   {
960     i = i1;
961     *iptr = i1;
962     return 0;
963   }
964 
965   i = points->InsertNextPoint(p);
966   pointData->InterpolateEdge(pointData, i, i0, i1, t);
967 
968   // Store the new index in the locator
969   *iptr = i;
970 
971   return 1;
972 }
973 
974 //----------------------------------------------------------------------------
ClipLines(vtkPoints * points,vtkDoubleArray * pointScalars,vtkPointData * pointData,vtkCCSEdgeLocator * edgeLocator,vtkCellArray * inputCells,vtkCellArray * outputLines,vtkCellData * inCellData,vtkCellData * outLineData)975 void vtkClipClosedSurface::ClipLines(
976   vtkPoints *points, vtkDoubleArray *pointScalars,
977   vtkPointData *pointData, vtkCCSEdgeLocator *edgeLocator,
978   vtkCellArray *inputCells, vtkCellArray *outputLines,
979   vtkCellData *inCellData, vtkCellData *outLineData)
980 {
981   vtkIdType numCells = inputCells->GetNumberOfCells();
982 
983   inputCells->InitTraversal();
984   for (vtkIdType cellId = 0; cellId < numCells; cellId++)
985   {
986     vtkIdType numPts = 0;
987     vtkIdType *pts = nullptr;
988     inputCells->GetNextCell(numPts, pts);
989 
990     vtkIdType i1 = pts[0];
991     double v1 = pointScalars->GetValue(i1);
992     int c1 = (v1 > 0);
993 
994     for (vtkIdType i = 1; i < numPts; i++)
995     {
996       vtkIdType i0 = i1;
997       double v0 = v1;
998       int c0 = c1;
999 
1000       i1 = pts[i];
1001       v1 = pointScalars->GetValue(i1);
1002       c1 = (v1 > 0);
1003 
1004       // If at least one point wasn't clipped
1005       if ( (c0 | c1) )
1006       {
1007         vtkIdType linePts[2];
1008         linePts[0] = i0;
1009         linePts[1] = i1;
1010 
1011         // If only one end was clipped, interpolate new point
1012         if ( (c0 ^ c1) )
1013         {
1014           vtkClipClosedSurface::InterpolateEdge(
1015             points, pointData, edgeLocator, this->Tolerance,
1016             i0, i1, v0, v1, linePts[c0]);
1017         }
1018 
1019         // If endpoints are different, insert the line segment
1020         if (linePts[0] != linePts[1])
1021         {
1022           vtkIdType newCellId = outputLines->InsertNextCell(2, linePts);
1023           outLineData->CopyData(inCellData, cellId, newCellId);
1024         }
1025       }
1026     }
1027   }
1028 }
1029 
1030 //----------------------------------------------------------------------------
ClipAndContourPolys(vtkPoints * points,vtkDoubleArray * pointScalars,vtkPointData * pointData,vtkCCSEdgeLocator * edgeLocator,int triangulate,vtkCellArray * inputCells,vtkCellArray * outputPolys,vtkCellArray * outputLines,vtkCellData * inCellData,vtkCellData * outPolyData,vtkCellData * outLineData)1031 void vtkClipClosedSurface::ClipAndContourPolys(
1032   vtkPoints *points, vtkDoubleArray *pointScalars, vtkPointData *pointData,
1033   vtkCCSEdgeLocator *edgeLocator, int triangulate,
1034   vtkCellArray *inputCells,
1035   vtkCellArray *outputPolys, vtkCellArray *outputLines,
1036   vtkCellData *inCellData,
1037   vtkCellData *outPolyData, vtkCellData *outLineData)
1038 {
1039   vtkIdList *idList = this->IdList;
1040 
1041   // How many sides for output polygons?
1042   int polyMax = VTK_INT_MAX;
1043   if (triangulate)
1044   {
1045     if (triangulate < 4)
1046     { // triangles only
1047       polyMax = 3;
1048     }
1049     else if (triangulate == 4)
1050     { // allow triangles and quads
1051       polyMax = 4;
1052     }
1053   }
1054 
1055   int triangulationFailure = 0;
1056 
1057   // Go through all cells and clip them.
1058   vtkIdType numCells = inputCells->GetNumberOfCells();
1059 
1060   inputCells->InitTraversal();
1061   for (vtkIdType cellId = 0; cellId < numCells; cellId++)
1062   {
1063     vtkIdType numPts = 0;
1064     vtkIdType *pts = nullptr;
1065     inputCells->GetNextCell(numPts, pts);
1066     idList->Reset();
1067 
1068     vtkIdType i1 = pts[numPts-1];
1069     double v1 = pointScalars->GetValue(i1);
1070     int c1 = (v1 > 0);
1071 
1072     // The ids for the current edge: init j0 to -1 if i1 will be clipped
1073     vtkIdType j0 = (c1 ? i1 : -1);
1074     vtkIdType j1 = 0;
1075 
1076     // To store the ids of the contour line
1077     vtkIdType linePts[2];
1078     linePts[0] = 0;
1079     linePts[1] = 0;
1080 
1081     for (vtkIdType i = 0; i < numPts; i++)
1082     {
1083       // Save previous point info
1084       vtkIdType i0 = i1;
1085       double v0 = v1;
1086       int c0 = c1;
1087 
1088       // Generate new point info
1089       i1 = pts[i];
1090       v1 = pointScalars->GetValue(i1);
1091       c1 = (v1 > 0);
1092 
1093       // If at least one edge end point wasn't clipped
1094       if ( (c0 | c1) )
1095       {
1096         // If only one end was clipped, interpolate new point
1097         if ( (c0 ^ c1) )
1098         {
1099           vtkClipClosedSurface::InterpolateEdge(
1100             points, pointData, edgeLocator, this->Tolerance,
1101             i0, i1, v0, v1, j1);
1102 
1103           if (j1 != j0)
1104           {
1105             idList->InsertNextId(j1);
1106             j0 = j1;
1107           }
1108 
1109           // Save as one end of the contour line
1110           linePts[c0] = j1;
1111         }
1112 
1113         if (c1)
1114         {
1115           j1 = i1;
1116 
1117           if (j1 != j0)
1118           {
1119             idList->InsertNextId(j1);
1120             j0 = j1;
1121           }
1122         }
1123       }
1124     }
1125 
1126     // Insert the clipped poly
1127     vtkIdType numPoints = idList->GetNumberOfIds();
1128 
1129     if (numPoints > polyMax)
1130     {
1131       vtkIdType newCellId = outputPolys->GetNumberOfCells();
1132 
1133       // Triangulate the poly and insert triangles into output.
1134       if (!this->TriangulatePolygon(idList, points, outputPolys))
1135       {
1136         triangulationFailure = 1;
1137       }
1138 
1139       // Copy the attribute data to the triangle cells
1140       vtkIdType nCells = outputPolys->GetNumberOfCells();
1141       for (; newCellId < nCells; newCellId++)
1142       {
1143         outPolyData->CopyData(inCellData, cellId, newCellId);
1144       }
1145     }
1146     else if (numPoints > 2)
1147     {
1148       // Insert the polygon without triangulating it
1149       vtkIdType newCellId = outputPolys->InsertNextCell(idList);
1150       outPolyData->CopyData(inCellData, cellId, newCellId);
1151     }
1152 
1153     // Insert the contour line if one was created
1154     if (linePts[0] != linePts[1])
1155     {
1156       vtkIdType newCellId = outputLines->InsertNextCell(2, linePts);
1157       outLineData->CopyData(inCellData, cellId, newCellId);
1158     }
1159   }
1160 
1161   if (triangulationFailure && this->TriangulationErrorDisplay)
1162   {
1163     vtkErrorMacro("Triangulation failed, output may not be watertight");
1164   }
1165 
1166   // Free up the idList memory
1167   idList->Initialize();
1168 }
1169 
1170 //----------------------------------------------------------------------------
BreakPolylines(vtkCellArray * inputLines,vtkCellArray * lines,vtkUnsignedCharArray * inputScalars,vtkIdType firstLineScalar,vtkUnsignedCharArray * scalars,const unsigned char color[3])1171 void vtkClipClosedSurface::BreakPolylines(
1172   vtkCellArray *inputLines, vtkCellArray *lines,
1173   vtkUnsignedCharArray *inputScalars, vtkIdType firstLineScalar,
1174   vtkUnsignedCharArray *scalars, const unsigned char color[3])
1175 {
1176   // The color for the lines
1177   unsigned char cellColor[3];
1178   cellColor[0] = color[0];
1179   cellColor[1] = color[1];
1180   cellColor[2] = color[2];
1181 
1182   // Break the input lines into segments
1183   inputLines->InitTraversal();
1184   vtkIdType cellId = 0;
1185   vtkIdType npts, *pts;
1186   while (inputLines->GetNextCell(npts, pts))
1187   {
1188     if (inputScalars)
1189     {
1190       inputScalars->GetTypedTuple(firstLineScalar + cellId++, cellColor);
1191     }
1192 
1193     for (vtkIdType i = 1; i < npts; i++)
1194     {
1195       lines->InsertNextCell(2);
1196       lines->InsertCellPoint(pts[i-1]);
1197       lines->InsertCellPoint(pts[i]);
1198 
1199       if (scalars)
1200       {
1201         scalars->InsertNextTypedTuple(cellColor);
1202       }
1203     }
1204   }
1205 }
1206 
1207 //----------------------------------------------------------------------------
CopyPolygons(vtkCellArray * inputPolys,vtkCellArray * polys,vtkUnsignedCharArray * inputScalars,vtkIdType firstPolyScalar,vtkUnsignedCharArray * polyScalars,const unsigned char color[3])1208 void vtkClipClosedSurface::CopyPolygons(
1209   vtkCellArray *inputPolys, vtkCellArray *polys,
1210   vtkUnsignedCharArray *inputScalars, vtkIdType firstPolyScalar,
1211   vtkUnsignedCharArray *polyScalars, const unsigned char color[3])
1212 {
1213   if (!inputPolys)
1214   {
1215     return;
1216   }
1217 
1218   polys->DeepCopy(inputPolys);
1219 
1220   if (polyScalars)
1221   {
1222     unsigned char scalarValue[3];
1223     scalarValue[0] = color[0];
1224     scalarValue[1] = color[1];
1225     scalarValue[2] = color[2];
1226 
1227     vtkIdType n = polys->GetNumberOfCells();
1228     polyScalars->SetNumberOfTuples(n);
1229 
1230     if (inputScalars)
1231     {
1232       for (vtkIdType i = 0; i < n; i++)
1233       {
1234         inputScalars->GetTypedTuple(i + firstPolyScalar, scalarValue);
1235         polyScalars->SetTypedTuple(i, scalarValue);
1236       }
1237     }
1238     else
1239     {
1240       for (vtkIdType i = 0; i < n; i++)
1241       {
1242         polyScalars->SetTypedTuple(i, scalarValue);
1243       }
1244     }
1245   }
1246 }
1247 
1248 //----------------------------------------------------------------------------
BreakTriangleStrips(vtkCellArray * inputStrips,vtkCellArray * polys,vtkUnsignedCharArray * inputScalars,vtkIdType firstStripScalar,vtkUnsignedCharArray * polyScalars,const unsigned char color[3])1249 void vtkClipClosedSurface::BreakTriangleStrips(
1250   vtkCellArray *inputStrips, vtkCellArray *polys,
1251   vtkUnsignedCharArray *inputScalars, vtkIdType firstStripScalar,
1252   vtkUnsignedCharArray *polyScalars, const unsigned char color[3])
1253 {
1254   if (!inputStrips)
1255   {
1256     return;
1257   }
1258 
1259   vtkIdType npts = 0;
1260   vtkIdType *pts = nullptr;
1261 
1262   inputStrips->InitTraversal();
1263 
1264   for (vtkIdType cellId = firstStripScalar;
1265        inputStrips->GetNextCell(npts, pts);
1266        cellId++)
1267   {
1268     vtkTriangleStrip::DecomposeStrip(npts, pts, polys);
1269 
1270     if (polyScalars)
1271     {
1272       unsigned char scalarValue[3];
1273       scalarValue[0] = color[0];
1274       scalarValue[1] = color[1];
1275       scalarValue[2] = color[2];
1276 
1277       if (inputScalars)
1278       {
1279         // If there are input scalars, use them instead of "color"
1280         inputScalars->GetTypedTuple(cellId, scalarValue);
1281       }
1282 
1283       vtkIdType n = npts - 3;
1284       vtkIdType m = polyScalars->GetNumberOfTuples();
1285       if (n >= 0)
1286       {
1287         // First insert is just to allocate space
1288         polyScalars->InsertTypedTuple(m+n, scalarValue);
1289 
1290         for (vtkIdType i = 0; i < n; i++)
1291         {
1292           polyScalars->SetTypedTuple(m+i, scalarValue);
1293         }
1294       }
1295     }
1296   }
1297 }
1298 
1299 //----------------------------------------------------------------------------
TriangulateContours(vtkPolyData * data,vtkIdType firstLine,vtkIdType numLines,vtkCellArray * outputPolys,const double normal[3])1300 void vtkClipClosedSurface::TriangulateContours(
1301   vtkPolyData *data, vtkIdType firstLine, vtkIdType numLines,
1302   vtkCellArray *outputPolys, const double normal[3])
1303 {
1304   // If no cut lines were generated, there's nothing to do
1305   if (numLines <= 0)
1306   {
1307     return;
1308   }
1309 
1310   double nnormal[3] = { -normal[0], -normal[1], -normal[2] };
1311   int rval = vtkContourTriangulator::TriangulateContours(
1312                data, firstLine, numLines, outputPolys, nnormal);
1313 
1314   if (rval == 0 && this->TriangulationErrorDisplay)
1315   {
1316     vtkErrorMacro("Triangulation failed, data may not be watertight.");
1317   }
1318 }
1319 
1320 // ---------------------------------------------------
TriangulatePolygon(vtkIdList * polygon,vtkPoints * points,vtkCellArray * triangles)1321 int vtkClipClosedSurface::TriangulatePolygon(
1322   vtkIdList *polygon, vtkPoints *points, vtkCellArray *triangles)
1323 {
1324   return vtkContourTriangulator::TriangulatePolygon(
1325            polygon, points, triangles);
1326 }
1327