1 /*==============================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkLabeledContourMapper.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 
16 #include "vtkLabeledContourMapper.h"
17 
18 #include "vtkCamera.h"
19 #include "vtkCellArray.h"
20 #include "vtkCoordinate.h"
21 #include "vtkDoubleArray.h"
22 #include "vtkExecutive.h"
23 #include "vtkInformation.h"
24 #include "vtkIntArray.h"
25 #include "vtkMatrix4x4.h"
26 #include "vtkMath.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkPointData.h"
29 #include "vtkPolyData.h"
30 #include "vtkPolyDataMapper.h"
31 #include "vtkRenderer.h"
32 #include "vtkRenderWindow.h"
33 #include "vtkTextActor3D.h"
34 #include "vtkTextProperty.h"
35 #include "vtkTextPropertyCollection.h"
36 #include "vtkTextRenderer.h"
37 #include "vtkTimerLog.h"
38 #include "vtkTransform.h"
39 #include "vtkVector.h"
40 #include "vtkVectorOperators.h"
41 #include "vtkWindow.h"
42 
43 #include <algorithm>
44 #include <cassert>
45 #include <cmath>
46 #include <map>
47 #include <sstream>
48 #include <string>
49 #include <vector>
50 
51 //------------------------------------------------------------------------------
52 struct LabelMetric
53 {
54   bool Valid;
55   double Value;
56   vtkTextProperty *TProp;
57   std::string Text;
58   // These measure the pixel size of the text texture:
59   vtkTuple<int, 4> BoundingBox;
60   vtkTuple<int, 2> Dimensions;
61 };
62 
63 //------------------------------------------------------------------------------
64 struct LabelInfo
65 {
66   // Position in actor space:
67   vtkVector3d Position;
68 
69   // Orientation (normalized, world space)
70   vtkVector3d RightW; // Left --> Right
71   vtkVector3d UpW; // Bottom --> Top
72 
73   // Orientation (normalized in world space, represented in actor space)
74   vtkVector3d RightA; // Left --> Right
75   vtkVector3d UpA; // Bottom --> Top
76 
77   // Corner locations (actor space):
78   vtkVector3d TLa;
79   vtkVector3d TRa;
80   vtkVector3d BRa;
81   vtkVector3d BLa;
82 
83   // Corner location (display space):
84   vtkVector2i TLd;
85   vtkVector2i TRd;
86   vtkVector2i BRd;
87   vtkVector2i BLd;
88 
89   // Factor to scale the text actor by:
90   double ScaleDisplayToActor;
91 };
92 
93 namespace {
94 
95 // Circular iterator through a vtkTextPropertyCollection -----------------------
96 class TextPropLoop
97 {
98   vtkTextPropertyCollection *TProps;
99 public:
TextPropLoop(vtkTextPropertyCollection * col)100   TextPropLoop(vtkTextPropertyCollection *col)
101     : TProps(col)
102   {
103     TProps->InitTraversal();
104   }
105 
Next()106   vtkTextProperty* Next()
107   {
108     // The input checks should fail if this is the case:
109     assert("No text properties set! Prerender check failed!" &&
110            TProps->GetNumberOfItems() != 0);
111 
112     vtkTextProperty *result = TProps->GetNextItem();
113     if (!result)
114     {
115       TProps->InitTraversal();
116       result = TProps->GetNextItem();
117       assert("Text property traversal error." && result != nullptr);
118     }
119     return result;
120   }
121 };
122 
123 //------------------------------------------------------------------------------
calculateSmoothness(double pathLength,double distance)124 double calculateSmoothness(double pathLength, double distance)
125 {
126   return (pathLength - distance) / distance;
127 }
128 
129 } // end anon namespace
130 
131 //------------------------------------------------------------------------------
132 struct vtkLabeledContourMapper::Private
133 {
134   // One entry per isoline.
135   std::vector<LabelMetric> LabelMetrics;
136 
137   // One LabelInfo per label groups by isoline.
138   std::vector<std::vector<LabelInfo> > LabelInfos;
139 
140   // Info for calculating display coordinates:
141   vtkTuple<double, 16> AMVP; // actor-model-view-projection matrix
142   vtkTuple<double, 16> ActorMatrix; // Actor model matrix
143   vtkTuple<double, 16> InverseActorMatrix; // Inverse Actor model matrix
144   vtkTuple<double, 4> ViewPort; // viewport
145   vtkTuple<double, 4> NormalizedViewPort; // see vtkViewport::ViewToNormalizedVP
146   vtkTuple<int, 2> WindowSize;
147   vtkTuple<int, 2> ViewPortSize;
148   vtkTuple<double, 2> DisplayOffset;
149   vtkTuple<double, 4> ViewportBounds;
150 
151   // Needed to orient the labels
152   vtkVector3d CameraRight;
153   vtkVector3d CameraUp;
154   vtkVector3d CameraForward;
155 
156   // Render times:
157   double PrepareTime;
158   double RenderTime;
159 
160   // Only want to print the stencil warning once:
161   bool AlreadyWarnedAboutStencils;
162 
163   // Project coordinates. Note that the vector objects must be unique.
164   void ActorToWorld(const vtkVector3d &actor, vtkVector3d &world) const;
165   void WorldToActor(const vtkVector3d &world, vtkVector3d &actor) const;
166   void ActorToDisplay(const vtkVector3d &actor, vtkVector2i &display) const;
167   void ActorToDisplay(const vtkVector3d &actor, vtkVector2d &display) const;
168 
169   // Camera axes:
170   bool SetViewInfo(vtkRenderer *ren, vtkActor *act);
171 
172   // Visibility test (display space):
173   template <typename ScalarType>
174   bool PixelIsVisible(const vtkVector2<ScalarType> &dispCoord) const;
175 
176   bool LineCanBeLabeled(vtkPoints *points, vtkIdType numIds,
177                         const vtkIdType *ids, const LabelMetric &metrics);
178 
179   // Determine the first smooth position on the line defined by ids that is
180   // 1.2x the length of the label (in display coordinates).
181   // The position will be no less than skipDistance along the line from the
182   // starting location. This can be used to ensure that labels are placed a
183   // minimum distance apart.
184   bool NextLabel(vtkPoints *points, vtkIdType &numIds, vtkIdType *&ids,
185                  const LabelMetric &metrics, LabelInfo &info,
186                  double targetSmoothness, double skipDistance);
187 
188   // Configure the text actor:
189   bool BuildLabel(vtkTextActor3D *actor, const LabelMetric &metric,
190                   const LabelInfo &info);
191 
192   // Compute the scaling factor and corner info for the label
193   void ComputeLabelInfo(LabelInfo &info, const LabelMetric &metrics);
194 
195   // Test if the display quads overlap:
196   bool TestOverlap(const LabelInfo &a, const LabelInfo &b);
197 };
198 
199 //------------------------------------------------------------------------------
vtkObjectFactoryNewMacro(vtkLabeledContourMapper)200 vtkObjectFactoryNewMacro(vtkLabeledContourMapper)
201 
202 //------------------------------------------------------------------------------
203 vtkLabeledContourMapper::vtkLabeledContourMapper()
204 {
205   this->SkipDistance = 0.;
206   this->LabelVisibility = true;
207   this->TextActors = nullptr;
208   this->NumberOfTextActors = 0;
209   this->NumberOfUsedTextActors = 0;
210 
211   this->StencilQuads = nullptr;
212   this->StencilQuadsSize = 0;
213   this->StencilQuadIndices = nullptr;
214   this->StencilQuadIndicesSize = 0;
215 
216   this->TextProperties = vtkSmartPointer<vtkTextPropertyCollection>::New();
217   vtkNew<vtkTextProperty> defaultTProp;
218   this->TextProperties->AddItem(defaultTProp);
219 
220   this->Internal = new vtkLabeledContourMapper::Private();
221   this->Internal->PrepareTime = 0.0;
222   this->Internal->RenderTime = 0.0;
223   this->Internal->AlreadyWarnedAboutStencils = false;
224 
225   this->Reset();
226 }
227 
228 //------------------------------------------------------------------------------
~vtkLabeledContourMapper()229 vtkLabeledContourMapper::~vtkLabeledContourMapper()
230 {
231   this->FreeStencilQuads();
232   this->FreeTextActors();
233 
234   delete this->Internal;
235 }
236 
237 //------------------------------------------------------------------------------
Render(vtkRenderer * ren,vtkActor * act)238 void vtkLabeledContourMapper::Render(vtkRenderer *ren, vtkActor *act)
239 {
240   if (vtkRenderWindow *renderWindow = ren->GetRenderWindow())
241   {
242     // Is the viewport's RenderWindow capturing GL2PS-special props?
243     if (renderWindow->GetCapturingGL2PSSpecialProps())
244     {
245         ren->CaptureGL2PSSpecialProp(act);
246     }
247   }
248 
249   // Make sure input data is synced
250   if (vtkAlgorithm *inputAlgorithm = this->GetInputAlgorithm())
251   {
252     inputAlgorithm->Update();
253   }
254 
255   if (!this->CheckInputs(ren))
256   {
257     return;
258   }
259 
260   if (!this->LabelVisibility)
261   {
262     this->RenderPolyData(ren, act);
263     return;
264   }
265 
266   if (this->CheckRebuild(ren, act))
267   {
268     double startPrep = vtkTimerLog::GetUniversalTime();
269 
270     this->Reset();
271 
272     if (!this->PrepareRender(ren, act))
273     {
274       return;
275     }
276 
277     if (!this->PlaceLabels())
278     {
279       return;
280     }
281 
282     if (!this->ResolveLabels())
283     {
284       return;
285     }
286 
287     if (!this->CreateLabels(act))
288     {
289       return;
290     }
291 
292     if (!this->BuildStencilQuads())
293     {
294       return;
295     }
296 
297     this->Internal->PrepareTime = vtkTimerLog::GetUniversalTime() - startPrep;
298     this->LabelBuildTime.Modified();
299   }
300 
301   double startRender = vtkTimerLog::GetUniversalTime();
302 
303   if (!this->ApplyStencil(ren, act))
304   {
305     return;
306   }
307 
308   if (!this->RenderPolyData(ren, act))
309   {
310     this->RemoveStencil(ren);
311     return;
312   }
313 
314   if (!this->RemoveStencil(ren))
315   {
316     return;
317   }
318 
319   if (!this->RenderLabels(ren, act))
320   {
321     return;
322   }
323 
324   this->Internal->RenderTime = vtkTimerLog::GetUniversalTime() - startRender;
325 }
326 
327 //------------------------------------------------------------------------------
SetInputData(vtkPolyData * input)328 void vtkLabeledContourMapper::SetInputData(vtkPolyData *input)
329 {
330   this->SetInputDataInternal(0, input);
331 }
332 
333 //------------------------------------------------------------------------------
GetInput()334 vtkPolyData *vtkLabeledContourMapper::GetInput()
335 {
336   return vtkPolyData::SafeDownCast(this->GetExecutive()->GetInputData(0, 0));
337 }
338 
339 //------------------------------------------------------------------------------
GetBounds()340 double *vtkLabeledContourMapper::GetBounds()
341 {
342   if (this->GetNumberOfInputConnections(0) == 0)
343   {
344     vtkMath::UninitializeBounds(this->Bounds);
345     return this->Bounds;
346   }
347   else
348   {
349     this->ComputeBounds();
350     return this->Bounds;
351   }
352 }
353 
354 //------------------------------------------------------------------------------
GetBounds(double bounds[])355 void vtkLabeledContourMapper::GetBounds(double bounds[])
356 {
357   this->Superclass::GetBounds(bounds);
358 }
359 
360 //------------------------------------------------------------------------------
SetTextProperty(vtkTextProperty * tprop)361 void vtkLabeledContourMapper::SetTextProperty(vtkTextProperty *tprop)
362 {
363   if (this->TextProperties->GetNumberOfItems() != 1 ||
364       this->TextProperties->GetItemAsObject(0) != tprop)
365   {
366     this->TextProperties->RemoveAllItems();
367     this->TextProperties->AddItem(tprop);
368     this->Modified();
369   }
370 }
371 
372 //------------------------------------------------------------------------------
SetTextProperties(vtkTextPropertyCollection * coll)373 void vtkLabeledContourMapper::SetTextProperties(vtkTextPropertyCollection *coll)
374 {
375   if (coll != this->TextProperties)
376   {
377     this->TextProperties = coll;
378     this->Modified();
379   }
380 }
381 
382 //------------------------------------------------------------------------------
GetTextProperties()383 vtkTextPropertyCollection *vtkLabeledContourMapper::GetTextProperties()
384 {
385   return this->TextProperties;
386 }
387 
388 //------------------------------------------------------------------------------
GetTextPropertyMapping()389 vtkDoubleArray *vtkLabeledContourMapper::GetTextPropertyMapping()
390 {
391   return this->TextPropertyMapping;
392 }
393 
394 //------------------------------------------------------------------------------
SetTextPropertyMapping(vtkDoubleArray * mapping)395 void vtkLabeledContourMapper::SetTextPropertyMapping(vtkDoubleArray *mapping)
396 {
397   if (this->TextPropertyMapping != mapping)
398   {
399     this->TextPropertyMapping = mapping;
400     this->Modified();
401   }
402 }
403 
404 //------------------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * win)405 void vtkLabeledContourMapper::ReleaseGraphicsResources(vtkWindow *win)
406 {
407   this->PolyDataMapper->ReleaseGraphicsResources(win);
408   for (vtkIdType i = 0; i < this->NumberOfTextActors; ++i)
409   {
410     this->TextActors[i]->ReleaseGraphicsResources(win);
411   }
412 }
413 
414 //------------------------------------------------------------------------------
ComputeBounds()415 void vtkLabeledContourMapper::ComputeBounds()
416 {
417   this->GetInput()->GetBounds(this->Bounds);
418 }
419 
420 //------------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)421 void vtkLabeledContourMapper::PrintSelf(ostream& os, vtkIndent indent)
422 {
423   this->Superclass::PrintSelf(os,indent);
424 
425   os << indent << "SkipDistance: " << this->SkipDistance << "\n"
426      << indent << "LabelVisibility: " << (this->LabelVisibility ? "On\n"
427                                                                : "Off\n")
428      << indent << "NumberOfTextActors: " << this->NumberOfTextActors << "\n"
429      << indent << "NumberOfUsedTextActors: "
430      << this->NumberOfUsedTextActors << "\n"
431      << indent << "StencilQuadsSize: " << this->StencilQuadsSize << "\n"
432      << indent << "StencilQuadIndicesSize: "
433      << this->StencilQuadIndicesSize << "\n"
434      << indent << "BuildTime: " << this->LabelBuildTime.GetMTime() << "\n"
435      << indent << "PolyDataMapper:\n";
436   this->PolyDataMapper->PrintSelf(os, indent.GetNextIndent());
437   os << indent << "TextProperties:\n";
438   this->TextProperties->PrintSelf(os, indent.GetNextIndent());
439   os << indent << "TextPropertyMapping:";
440   if (this->TextPropertyMapping)
441   {
442     os << "\n";
443     this->TextPropertyMapping->PrintSelf(os, indent.GetNextIndent());
444   }
445   else
446   {
447     os << " (nullptr)\n";
448   }
449 
450 }
451 
452 //------------------------------------------------------------------------------
FillInputPortInformation(int vtkNotUsed (port),vtkInformation * info)453 int vtkLabeledContourMapper::FillInputPortInformation(
454     int vtkNotUsed(port), vtkInformation* info)
455 {
456   info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
457   return 1;
458 }
459 
460 //------------------------------------------------------------------------------
Reset()461 void vtkLabeledContourMapper::Reset()
462 {
463   this->Internal->LabelMetrics.clear();
464   this->Internal->LabelInfos.clear();
465 
466   this->TextProperties->InitTraversal();
467   while (vtkTextProperty *tprop = this->TextProperties->GetNextItem())
468   {
469     tprop->SetJustificationToCentered();
470     tprop->SetVerticalJustificationToCentered();
471   }
472 }
473 
474 //------------------------------------------------------------------------------
CheckInputs(vtkRenderer * ren)475 bool vtkLabeledContourMapper::CheckInputs(vtkRenderer *ren)
476 {
477   vtkPolyData *input = this->GetInput();
478   if (!input)
479   {
480     vtkErrorMacro(<<"No input data!")
481     return false;
482   }
483 
484   if (!input->GetPoints())
485   {
486     vtkErrorMacro(<<"No points in dataset!");
487     return false;
488   }
489 
490   if (!input->GetPointData())
491   {
492     vtkErrorMacro(<<"No point data in dataset!");
493     return false;
494   }
495 
496   vtkCellArray *lines = input->GetLines();
497   if (!lines)
498   {
499     vtkErrorMacro(<<"No lines in dataset!");
500     return false;
501   }
502 
503   vtkDataArray *scalars = input->GetPointData()->GetScalars();
504   if (!scalars)
505   {
506     vtkErrorMacro(<<"No scalars in dataset!");
507     return false;
508   }
509 
510   vtkTextRenderer *tren = vtkTextRenderer::GetInstance();
511   if (!tren)
512   {
513     vtkErrorMacro(<<"Text renderer unavailable.");
514     return false;
515   }
516 
517   if (this->TextProperties->GetNumberOfItems() == 0)
518   {
519     vtkErrorMacro(<<"No text properties set!");
520     return false;
521   }
522 
523   // Print a warning if stenciling is not enabled:
524   vtkRenderWindow *win = ren->GetRenderWindow();
525   if (!this->Internal->AlreadyWarnedAboutStencils && win)
526   {
527     if (win->GetStencilCapable() == 0)
528     {
529       vtkWarningMacro(<< "Stenciling is not enabled in the render window. "
530                          "Isoline labels will have artifacts. To fix this, "
531                          "call vtkRenderWindow::StencilCapableOn().")
532       this->Internal->AlreadyWarnedAboutStencils = true;
533     }
534   }
535 
536   return true;
537 }
538 
539 //------------------------------------------------------------------------------
CheckRebuild(vtkRenderer *,vtkActor * act)540 bool vtkLabeledContourMapper::CheckRebuild(vtkRenderer *, vtkActor *act)
541 {
542   // Get the highest mtime for the text properties:
543   vtkMTimeType tPropMTime = this->TextProperties->GetMTime();
544   this->TextProperties->InitTraversal();
545   while (vtkTextProperty *tprop = this->TextProperties->GetNextItem())
546   {
547     tPropMTime = std::max(tPropMTime, tprop->GetMTime());
548   }
549 
550   // Are we out of date?
551   if (this->LabelBuildTime.GetMTime() < this->GetInput()->GetMTime() ||
552       this->LabelBuildTime.GetMTime() < tPropMTime)
553   {
554     return true;
555   }
556 
557   // Is there enough time allocated? (i.e. is this not an interactive render?)
558   if (act->GetAllocatedRenderTime() >=
559       (this->Internal->RenderTime + this->Internal->PrepareTime))
560   {
561     return true;
562   }
563 
564   return false;
565 }
566 
567 //------------------------------------------------------------------------------
PrepareRender(vtkRenderer * ren,vtkActor * act)568 bool vtkLabeledContourMapper::PrepareRender(vtkRenderer *ren, vtkActor *act)
569 {
570   if (!this->Internal->SetViewInfo(ren, act))
571   {
572     return false;
573   }
574 
575   // Already checked that these exist in CheckInputs()
576   vtkPolyData *input = this->GetInput();
577   vtkCellArray *lines = input->GetLines();
578   vtkDataArray *scalars = input->GetPointData()->GetScalars();
579   vtkTextRenderer *tren = vtkTextRenderer::GetInstance();
580   if (!tren)
581   {
582     vtkErrorMacro(<< "Text renderer unavailable.");
583     return false;
584   }
585 
586   // Maps scalar values to text properties:
587   typedef std::map<double, vtkTextProperty*> LabelPropertyMapType;
588   LabelPropertyMapType labelMap;
589 
590   // Initialize with the user-requested mapping, if it exists.
591   if (this->TextPropertyMapping != nullptr)
592   {
593     vtkDoubleArray::Iterator valIt = this->TextPropertyMapping->Begin();
594     vtkDoubleArray::Iterator valItEnd = this->TextPropertyMapping->End();
595     TextPropLoop tprops(this->TextProperties);
596     for (; valIt != valItEnd; ++valIt)
597     {
598       labelMap.insert(std::make_pair(*valIt, tprops.Next()));
599     }
600   }
601 
602   // Create the list of metrics, but no text property information yet.
603   vtkIdType numPts;
604   vtkIdType *ids;
605   for (lines->InitTraversal(); lines->GetNextCell(numPts, ids);)
606   {
607     this->Internal->LabelMetrics.push_back(LabelMetric());
608     LabelMetric &metric = this->Internal->LabelMetrics.back();
609     if (!(metric.Valid = (numPts > 0)))
610     {
611       // Mark as invalid and skip if there are no points.
612       continue;
613     }
614     metric.Value = scalars->GetComponent(ids[0], 0);
615     metric.Value = std::fabs(metric.Value) > 1e-6 ? metric.Value : 0.0;
616     std::ostringstream str;
617     str << metric.Value;
618     metric.Text = str.str();
619 
620     // Beware future maintainers: The following line of code has been carefully
621     // crafted to reach a zen-like harmony of compatibility between various
622     // compilers that have differing syntactic requirements for creating a
623     // pair containing a nullptr:
624     // - Pedantically strict C++11 compilers (e.g. MSVC 2012) will not compile:
625     //     std::make_pair<double, X*>(someDouble, nullptr);
626     //   or any make_pair call with explicit template args and value arguments,
627     //   as the signature expects an rvalue.
628 
629     // The value will be replaced in the next loop:
630     labelMap.insert(std::pair<double, vtkTextProperty*>(
631                       metric.Value, static_cast<vtkTextProperty*>(nullptr)));
632   }
633 
634   // Now that all present scalar values are known, assign text properties:
635   TextPropLoop tprops(this->TextProperties);
636   typedef LabelPropertyMapType::iterator LabelPropertyMapIter;
637   for (LabelPropertyMapIter it = labelMap.begin(), itEnd = labelMap.end();
638        it != itEnd; ++it)
639   {
640     if (!it->second) // Skip if initialized from TextPropertyMapping
641     {
642       it->second = tprops.Next();
643     }
644   }
645 
646   // Update metrics with appropriate text info:
647   typedef std::vector<LabelMetric>::iterator MetricsIter;
648   for (MetricsIter it = this->Internal->LabelMetrics.begin(),
649        itEnd = this->Internal->LabelMetrics.end(); it != itEnd; ++it)
650   {
651     if (!it->Valid)
652     {
653       continue;
654     }
655 
656     // Look up text property for the scalar value:
657     LabelPropertyMapIter tpropIt = labelMap.find(it->Value);
658     assert("No text property assigned for scalar value." &&
659            tpropIt != labelMap.end());
660     it->TProp = tpropIt->second;
661 
662     // Assign bounding box/dims.
663     if (!tren->GetBoundingBox(it->TProp, it->Text, it->BoundingBox.GetData(),
664                               vtkTextActor3D::GetRenderedDPI()))
665     {
666       vtkErrorMacro(<<"Error calculating bounding box for string '"
667                     << it->Text << "'.");
668       return false;
669     }
670     it->Dimensions[0] = it->BoundingBox[1] - it->BoundingBox[0] + 1;
671     it->Dimensions[1] = it->BoundingBox[3] - it->BoundingBox[2] + 1;
672   }
673 
674   return true;
675 }
676 
677 //------------------------------------------------------------------------------
PlaceLabels()678 bool vtkLabeledContourMapper::PlaceLabels()
679 {
680   vtkPolyData *input = this->GetInput();
681   vtkPoints *points = input->GetPoints();
682   vtkCellArray *lines = input->GetLines();
683 
684   // Progression of smoothness tolerances to use.
685   std::vector<double> tols;
686   tols.push_back(0.010);
687   tols.push_back(0.025);
688   tols.push_back(0.050);
689   tols.push_back(0.100);
690   tols.push_back(0.200);
691   tols.push_back(0.300);
692 
693   typedef std::vector<LabelMetric>::const_iterator MetricsIterator;
694   MetricsIterator metric = this->Internal->LabelMetrics.begin();
695 
696   // Identify smooth parts of the isoline for labeling
697   vtkIdType numIds;
698   vtkIdType *origIds;
699   this->Internal->LabelInfos.reserve(this->Internal->LabelMetrics.size());
700   for (lines->InitTraversal(); lines->GetNextCell(numIds, origIds); ++metric)
701   {
702     assert(metric != this->Internal->LabelMetrics.end());
703 
704     this->Internal->LabelInfos.push_back(std::vector<LabelInfo>());
705 
706     // Test if it is possible to place a label (e.g. the line is big enough
707     // to not be completely obscured)
708     if (this->Internal->LineCanBeLabeled(points, numIds, origIds, *metric))
709     {
710       std::vector<LabelInfo> &infos = this->Internal->LabelInfos.back();
711       LabelInfo info;
712       // If no labels are found, increase the tolerance:
713       for (std::vector<double>::const_iterator it = tols.begin(),
714            itEnd = tols.end(); it != itEnd && infos.empty(); ++it)
715       {
716         vtkIdType nIds = numIds;
717         vtkIdType *ids = origIds;
718         while (this->Internal->NextLabel(points, nIds, ids, *metric, info, *it,
719                                          this->SkipDistance))
720         {
721           infos.push_back(info);
722         }
723       }
724     }
725   }
726 
727   return true;
728 }
729 
730 //------------------------------------------------------------------------------
ResolveLabels()731 bool vtkLabeledContourMapper::ResolveLabels()
732 {
733   typedef std::vector<LabelInfo>::iterator InnerIterator;
734   typedef std::vector<std::vector<LabelInfo> >::iterator OuterIterator;
735 
736   bool removedA = false;
737   bool removedB = false;
738 
739   OuterIterator outerA = this->Internal->LabelInfos.begin();
740   OuterIterator outerEnd = this->Internal->LabelInfos.end();
741   while (outerA != outerEnd)
742   {
743     InnerIterator innerA = outerA->begin();
744     InnerIterator innerAEnd = outerA->end();
745     while (innerA != innerAEnd)
746     {
747       removedA = false;
748       OuterIterator outerB = outerA;
749       while (!removedA && outerB != outerEnd)
750       {
751         InnerIterator innerB = outerA == outerB ? innerA + 1 : outerB->begin();
752         InnerIterator innerBEnd = outerB->end();
753         while (!removedA && innerB != innerBEnd)
754         {
755           removedB = false;
756           // Does innerA overlap with innerB?
757           if (this->Internal->TestOverlap(*innerA, *innerB))
758           {
759             // Remove the label that has the most labels for its isoline:
760             if (outerA->size() > outerB->size())
761             {
762               // Remove innerA
763               innerA = outerA->erase(innerA);
764               innerAEnd = outerA->end();
765               removedA = true;
766             }
767             else
768             {
769               // Remove innerB
770               // Need to update A's iterators if outerA == outerB
771               if (outerA == outerB)
772               {
773                 // We know that aIdx < bIdx, so removing B won't change
774                 // the position of A:
775                 size_t aIdx = innerA - outerA->begin();
776                 innerB = outerB->erase(innerB);
777                 innerBEnd = outerB->end();
778                 innerA = outerA->begin() + aIdx;
779                 innerAEnd = outerA->end();
780               }
781               else
782               {
783                 innerB = outerB->erase(innerB);
784                 innerBEnd = outerB->end();
785               }
786               removedB = true;
787             }
788           }
789           // Erase will increment B if we removed it.
790           if (!removedB)
791           {
792             ++innerB;
793           }
794         }
795         ++outerB;
796       }
797       // Erase will increment A if we removed it.
798       if (!removedA)
799       {
800         ++innerA;
801       }
802     }
803     ++outerA;
804   }
805 
806   return true;
807 }
808 
809 //------------------------------------------------------------------------------
CreateLabels(vtkActor *)810 bool vtkLabeledContourMapper::CreateLabels(vtkActor *)
811 {
812   typedef std::vector<LabelMetric> MetricVector;
813   typedef std::vector<LabelInfo> InfoVector;
814 
815   std::vector<InfoVector>::const_iterator outerLabels =
816       this->Internal->LabelInfos.begin();
817   std::vector<InfoVector>::const_iterator outerLabelsEnd =
818       this->Internal->LabelInfos.end();
819 
820   // count the number of labels:
821   vtkIdType numLabels = 0;
822   while (outerLabels != outerLabelsEnd)
823   {
824     numLabels += static_cast<vtkIdType>((outerLabels++)->size());
825   }
826 
827   if (!this->AllocateTextActors(numLabels))
828   {
829     vtkErrorMacro(<< "Error while allocating text actors.");
830     return false;
831   }
832 
833   outerLabels = this->Internal->LabelInfos.begin();
834   MetricVector::const_iterator metrics = this->Internal->LabelMetrics.begin();
835   MetricVector::const_iterator metricsEnd = this->Internal->LabelMetrics.end();
836   vtkTextActor3D **actor = this->TextActors;
837   vtkTextActor3D **actorEnd = this->TextActors + this->NumberOfUsedTextActors;
838 
839   while (metrics != metricsEnd &&
840          outerLabels != outerLabelsEnd &&
841          actor != actorEnd)
842   {
843     for (InfoVector::const_iterator label = outerLabels->begin(),
844          labelEnd = outerLabels->end(); label != labelEnd; ++label)
845     {
846       this->Internal->BuildLabel(*actor, *metrics, *label);
847       ++actor;
848     }
849     ++metrics;
850     ++outerLabels;
851   }
852 
853   return true;
854 }
855 
856 //------------------------------------------------------------------------------
ApplyStencil(vtkRenderer *,vtkActor *)857 bool vtkLabeledContourMapper::ApplyStencil(vtkRenderer *, vtkActor *)
858 {
859   // Handled in backend override.
860   return true;
861 }
862 
863 //------------------------------------------------------------------------------
RenderPolyData(vtkRenderer * ren,vtkActor * act)864 bool vtkLabeledContourMapper::RenderPolyData(vtkRenderer *ren, vtkActor *act)
865 {
866   this->PolyDataMapper->SetInputConnection(this->GetInputConnection(0, 0));
867   this->PolyDataMapper->Render(ren, act);
868   return true;
869 }
870 
871 //------------------------------------------------------------------------------
RemoveStencil(vtkRenderer *)872 bool vtkLabeledContourMapper::RemoveStencil(vtkRenderer *)
873 {
874   // Handled in backend override.
875   return true;
876 }
877 
878 //------------------------------------------------------------------------------
RenderLabels(vtkRenderer * ren,vtkActor *)879 bool vtkLabeledContourMapper::RenderLabels(vtkRenderer *ren, vtkActor *)
880 {
881   for (vtkIdType i = 0; i < this->NumberOfUsedTextActors; ++i)
882   {
883     // Needed for GL2PS capture:
884     this->TextActors[i]->RenderOpaqueGeometry(ren);
885     // Actually draw:
886     this->TextActors[i]->RenderTranslucentPolygonalGeometry(ren);
887   }
888   return true;
889 }
890 
891 //------------------------------------------------------------------------------
AllocateTextActors(vtkIdType num)892 bool vtkLabeledContourMapper::AllocateTextActors(vtkIdType num)
893 {
894   if (num != this->NumberOfUsedTextActors)
895   {
896     if (this->NumberOfTextActors < num ||
897         this->NumberOfTextActors > 2 * num)
898     {
899       this->FreeTextActors();
900 
901       // Leave some room to grow:
902       this->NumberOfTextActors = num * 1.2;
903 
904       this->TextActors = new vtkTextActor3D*[this->NumberOfTextActors];
905       for (vtkIdType i = 0; i < this->NumberOfTextActors; ++i)
906       {
907         this->TextActors[i] = vtkTextActor3D::New();
908       }
909     }
910 
911     this->NumberOfUsedTextActors = num;
912   }
913 
914   return true;
915 }
916 
917 //------------------------------------------------------------------------------
FreeTextActors()918 bool vtkLabeledContourMapper::FreeTextActors()
919 {
920   for (vtkIdType i = 0; i < this->NumberOfTextActors; ++i)
921   {
922     this->TextActors[i]->Delete();
923   }
924 
925   delete [] this->TextActors;
926   this->TextActors = nullptr;
927   this->NumberOfTextActors = 0;
928   this->NumberOfUsedTextActors = 0;
929   return true;
930 }
931 
932 //------------------------------------------------------------------------------
FreeStencilQuads()933 void vtkLabeledContourMapper::FreeStencilQuads()
934 {
935   if (this->StencilQuads)
936   {
937     delete [] this->StencilQuads;
938     this->StencilQuads = nullptr;
939     this->StencilQuadsSize = 0;
940 
941     delete [] this->StencilQuadIndices;
942     this->StencilQuadIndices = nullptr;
943     this->StencilQuadIndicesSize = 0;
944   }
945 }
946 
947 //------------------------------------------------------------------------------
BuildStencilQuads()948 bool vtkLabeledContourMapper::BuildStencilQuads()
949 {
950   vtkIdType quadCount = this->NumberOfUsedTextActors * 12;
951   vtkIdType idxCount = this->NumberOfUsedTextActors * 6;
952   if (quadCount != this->StencilQuadsSize)
953   {
954     this->FreeStencilQuads();
955     this->StencilQuads = new float[quadCount];
956     this->StencilQuadsSize = quadCount;
957     this->StencilQuadIndices = new unsigned int[idxCount];
958     this->StencilQuadIndicesSize = idxCount;
959   }
960 
961   unsigned int qIndex = 0; // quad array index
962   unsigned int iIndex = 0; // index array index
963   unsigned int eIndex = 0; // index array element
964 
965   typedef std::vector<LabelInfo>::const_iterator InnerIterator;
966   typedef std::vector<std::vector<LabelInfo> >::const_iterator OuterIterator;
967 
968   for (OuterIterator out = this->Internal->LabelInfos.begin(),
969        outEnd = this->Internal->LabelInfos.end(); out != outEnd; ++out)
970   {
971     for (InnerIterator in = out->begin(), inEnd = out->end(); in != inEnd; ++in)
972     {
973       this->StencilQuads[qIndex +  0] = static_cast<float>(in->TLa[0]);
974       this->StencilQuads[qIndex +  1] = static_cast<float>(in->TLa[1]);
975       this->StencilQuads[qIndex +  2] = static_cast<float>(in->TLa[2]);
976       this->StencilQuads[qIndex +  3] = static_cast<float>(in->TRa[0]);
977       this->StencilQuads[qIndex +  4] = static_cast<float>(in->TRa[1]);
978       this->StencilQuads[qIndex +  5] = static_cast<float>(in->TRa[2]);
979       this->StencilQuads[qIndex +  6] = static_cast<float>(in->BRa[0]);
980       this->StencilQuads[qIndex +  7] = static_cast<float>(in->BRa[1]);
981       this->StencilQuads[qIndex +  8] = static_cast<float>(in->BRa[2]);
982       this->StencilQuads[qIndex +  9] = static_cast<float>(in->BLa[0]);
983       this->StencilQuads[qIndex + 10] = static_cast<float>(in->BLa[1]);
984       this->StencilQuads[qIndex + 11] = static_cast<float>(in->BLa[2]);
985 
986       this->StencilQuadIndices[iIndex + 0] = eIndex + 0;
987       this->StencilQuadIndices[iIndex + 1] = eIndex + 1;
988       this->StencilQuadIndices[iIndex + 2] = eIndex + 2;
989       this->StencilQuadIndices[iIndex + 3] = eIndex + 0;
990       this->StencilQuadIndices[iIndex + 4] = eIndex + 2;
991       this->StencilQuadIndices[iIndex + 5] = eIndex + 3;
992 
993       qIndex += 12;
994       iIndex += 6;
995       eIndex += 4;
996     }
997   }
998 
999   return true;
1000 }
1001 
1002 //------------------------------------------------------------------------------
ActorToWorld(const vtkVector3d & in,vtkVector3d & out) const1003 void vtkLabeledContourMapper::Private::ActorToWorld(const vtkVector3d &in,
1004                                                     vtkVector3d &out) const
1005 {
1006   const vtkTuple<double, 16> &x = this->ActorMatrix;
1007   double w;
1008   out[0] = in[0] * x[0]  + in[1] * x[1]  + in[2] * x[2]  + x[3];
1009   out[1] = in[0] * x[4]  + in[1] * x[5]  + in[2] * x[6]  + x[7];
1010   out[2] = in[0] * x[8]  + in[1] * x[9]  + in[2] * x[10] + x[11];
1011   w      = in[0] * x[12] + in[1] * x[13] + in[2] * x[14] + x[15];
1012   out = out * (1. / w);
1013 }
1014 
1015 //------------------------------------------------------------------------------
WorldToActor(const vtkVector3d & in,vtkVector3d & out) const1016 void vtkLabeledContourMapper::Private::WorldToActor(const vtkVector3d &in,
1017                                                     vtkVector3d &out) const
1018 {
1019   const vtkTuple<double, 16> &x = this->InverseActorMatrix;
1020   double w;
1021   out[0] = in[0] * x[0]  + in[1] * x[1]  + in[2] * x[2]  + x[3];
1022   out[1] = in[0] * x[4]  + in[1] * x[5]  + in[2] * x[6]  + x[7];
1023   out[2] = in[0] * x[8]  + in[1] * x[9]  + in[2] * x[10] + x[11];
1024   w      = in[0] * x[12] + in[1] * x[13] + in[2] * x[14] + x[15];
1025   out = out * (1. / w);
1026 }
1027 
1028 //------------------------------------------------------------------------------
ActorToDisplay(const vtkVector3d & actor,vtkVector2i & out) const1029 void vtkLabeledContourMapper::Private::ActorToDisplay(const vtkVector3d &actor,
1030                                                       vtkVector2i &out) const
1031 {
1032   vtkVector2d v;
1033   this->ActorToDisplay(actor, v);
1034   out = vtkVector2i(v.Cast<int>().GetData());
1035 }
1036 
1037 //------------------------------------------------------------------------------
ActorToDisplay(const vtkVector3d & actor,vtkVector2d & v) const1038 void vtkLabeledContourMapper::Private::ActorToDisplay(const vtkVector3d &actor,
1039                                                       vtkVector2d &v) const
1040 {
1041   // This is adapted from vtkCoordinate's world to display conversion. We
1042   // reimplement it here for efficiency.
1043 
1044   // vtkRenderer::WorldToView (AMVP includes the actor matrix, too)
1045   const vtkTuple<double, 16> &x = this->AMVP;
1046   double w;
1047   v[0] = actor[0] * x[0]  + actor[1] * x[1]  + actor[2] * x[2]  + x[3];
1048   v[1] = actor[0] * x[4]  + actor[1] * x[5]  + actor[2] * x[6]  + x[7];
1049   w    = actor[0] * x[12] + actor[1] * x[13] + actor[2] * x[14] + x[15];
1050   v = v * (1. / w);
1051 
1052   // vtkViewport::ViewToNormalizedViewport
1053   v[0] = this->NormalizedViewPort[0] + ((v[0] + 1.) / 2.) *
1054       (this->NormalizedViewPort[2] - this->NormalizedViewPort[0]);
1055   v[1] = this->NormalizedViewPort[1] + ((v[1] + 1.) / 2.) *
1056       (this->NormalizedViewPort[3] - this->NormalizedViewPort[1]);
1057   v[0] = (v[0] - this->ViewPort[0]) /
1058       (this->ViewPort[2] - this->ViewPort[0]);
1059   v[1] = (v[1] - this->ViewPort[1]) /
1060       (this->ViewPort[3] - this->ViewPort[1]);
1061 
1062   // vtkViewport::NormalizedViewportToViewport
1063   v[0] *= this->ViewPortSize[0] - 1.;
1064   v[1] *= this->ViewPortSize[1] - 1.;
1065 
1066   // vtkViewport::ViewportToNormalizedDisplay
1067   // vtkViewport::NormalizedDisplayToDisplay
1068   v[0] += this->DisplayOffset[0];
1069   v[1] += this->DisplayOffset[1];
1070 }
1071 
1072 //------------------------------------------------------------------------------
SetViewInfo(vtkRenderer * ren,vtkActor * act)1073 bool vtkLabeledContourMapper::Private::SetViewInfo(vtkRenderer *ren,
1074                                                    vtkActor *act)
1075 {
1076   vtkCamera *cam = ren->GetActiveCamera();
1077   if (!cam)
1078   {
1079     vtkGenericWarningMacro(<<"No active camera on renderer.");
1080     return false;
1081   }
1082 
1083   vtkMatrix4x4 *mat = cam->GetModelViewTransformMatrix();
1084   this->CameraRight.Set(mat->GetElement(0, 0),
1085                         mat->GetElement(0, 1),
1086                         mat->GetElement(0, 2));
1087   this->CameraUp.Set(mat->GetElement(1, 0),
1088                      mat->GetElement(1, 1),
1089                      mat->GetElement(1, 2));
1090   this->CameraForward.Set(mat->GetElement(2, 0),
1091                           mat->GetElement(2, 1),
1092                           mat->GetElement(2, 2));
1093 
1094   // figure out the same aspect ratio used by the render engine
1095   // (see vtkOpenGLCamera::Render())
1096   int  lowerLeft[2];
1097   int usize, vsize;
1098   double aspect1[2];
1099   double aspect2[2];
1100   ren->GetTiledSizeAndOrigin(&usize, &vsize, lowerLeft, lowerLeft+1);
1101   ren->ComputeAspect();
1102   ren->GetAspect(aspect1);
1103   ren->vtkViewport::ComputeAspect();
1104   ren->vtkViewport::GetAspect(aspect2);
1105   double aspectModification = (aspect1[0] * aspect2[1]) /
1106                               (aspect1[1] * aspect2[0]);
1107   double aspect = aspectModification * usize / vsize;
1108 
1109   // Get the mvp (mcdc) matrix
1110   double mvp[16];
1111   mat = cam->GetCompositeProjectionTransformMatrix(aspect, -1, 1);
1112   vtkMatrix4x4::DeepCopy(mvp, mat);
1113 
1114   // Apply the actor's matrix:
1115   vtkMatrix4x4::DeepCopy(this->ActorMatrix.GetData(), act->GetMatrix());
1116   vtkMatrix4x4::Multiply4x4(mvp, this->ActorMatrix.GetData(),
1117                             this->AMVP.GetData());
1118 
1119   vtkMatrix4x4::Invert(this->ActorMatrix.GetData(),
1120                        this->InverseActorMatrix.GetData());
1121 
1122   if (vtkWindow *win = ren->GetVTKWindow())
1123   {
1124     int *size = win->GetSize();
1125     this->WindowSize[0] = size[0];
1126     this->WindowSize[1] = size[1];
1127 
1128     size = ren->GetSize();
1129     this->ViewPortSize[0] = size[0];
1130     this->ViewPortSize[1] = size[1];
1131 
1132     ren->GetViewport(this->ViewPort.GetData());
1133 
1134     double *tvport = win->GetTileViewport();
1135     this->NormalizedViewPort[0] = std::max(this->ViewPort[0], tvport[0]);
1136     this->NormalizedViewPort[1] = std::max(this->ViewPort[1], tvport[1]);
1137     this->NormalizedViewPort[2] = std::min(this->ViewPort[2], tvport[2]);
1138     this->NormalizedViewPort[3] = std::min(this->ViewPort[3], tvport[3]);
1139 
1140     this->ViewportBounds[0] = this->ViewPort[0] * this->WindowSize[0];
1141     this->ViewportBounds[1] = this->ViewPort[2] * this->WindowSize[0];
1142     this->ViewportBounds[2] = this->ViewPort[1] * this->WindowSize[1];
1143     this->ViewportBounds[3] = this->ViewPort[3] * this->WindowSize[1];
1144 
1145     this->DisplayOffset[0] = static_cast<double>(this->ViewportBounds[0]) + 0.5;
1146     this->DisplayOffset[1] = static_cast<double>(this->ViewportBounds[2]) + 0.5;
1147   }
1148   else
1149   {
1150     vtkGenericWarningMacro(<<"No render window present.");
1151     return false;
1152   }
1153 
1154   return true;
1155 }
1156 
1157 //------------------------------------------------------------------------------
LineCanBeLabeled(vtkPoints * points,vtkIdType numIds,const vtkIdType * ids,const LabelMetric & metrics)1158 bool vtkLabeledContourMapper::Private::LineCanBeLabeled(
1159     vtkPoints *points, vtkIdType numIds, const vtkIdType *ids,
1160     const LabelMetric &metrics)
1161 {
1162   vtkTuple<int, 4> bbox(0);
1163   vtkVector3d actorCoord;
1164   vtkVector2i displayCoord;
1165   if (numIds > 0)
1166   {
1167     do
1168     {
1169       points->GetPoint(*(ids++), actorCoord.GetData());
1170       this->ActorToDisplay(actorCoord, displayCoord);
1171       --numIds;
1172     }
1173     while (numIds > 0 && !this->PixelIsVisible(displayCoord));
1174 
1175     if (!this->PixelIsVisible(displayCoord))
1176     {
1177       // No visible points
1178       return false;
1179     }
1180 
1181     bbox[0] = displayCoord.GetX();
1182     bbox[1] = displayCoord.GetX();
1183     bbox[2] = displayCoord.GetY();
1184     bbox[3] = displayCoord.GetY();
1185   }
1186   while (numIds-- > 0)
1187   {
1188     points->GetPoint(*(ids++), actorCoord.GetData());
1189     this->ActorToDisplay(actorCoord, displayCoord);
1190     if (this->PixelIsVisible(displayCoord))
1191     {
1192       bbox[0] = std::min(bbox[0], displayCoord.GetX());
1193       bbox[1] = std::max(bbox[1], displayCoord.GetX());
1194       bbox[2] = std::min(bbox[2], displayCoord.GetY());
1195       bbox[3] = std::max(bbox[3], displayCoord.GetY());
1196     }
1197   }
1198 
1199   // Must be at least twice the label length in at least one direction:
1200   return (metrics.Dimensions[0] * 2 < bbox[1] - bbox[0] ||
1201           metrics.Dimensions[0] * 2 < bbox[3] - bbox[2]);
1202 }
1203 
1204 //------------------------------------------------------------------------------
1205 template <typename ScalarType>
PixelIsVisible(const vtkVector2<ScalarType> & dispCoord) const1206 bool vtkLabeledContourMapper::Private::PixelIsVisible(
1207     const vtkVector2<ScalarType> &dispCoord) const
1208 {
1209   return (dispCoord.GetX() >= this->ViewportBounds[0] &&
1210           dispCoord.GetX() <= this->ViewportBounds[1] &&
1211           dispCoord.GetY() >= this->ViewportBounds[2] &&
1212           dispCoord.GetY() <= this->ViewportBounds[3]);
1213 }
1214 
1215 //------------------------------------------------------------------------------
NextLabel(vtkPoints * points,vtkIdType & numIds,vtkIdType * & ids,const LabelMetric & metrics,LabelInfo & info,double targetSmoothness,double skipDistance)1216 bool vtkLabeledContourMapper::Private::NextLabel(
1217     vtkPoints *points, vtkIdType &numIds, vtkIdType *&ids,
1218     const LabelMetric &metrics, LabelInfo &info, double targetSmoothness,
1219     double skipDistance)
1220 {
1221   if (numIds < 3)
1222   {
1223     return false;
1224   }
1225 
1226   // First point in this call to NextLabel (index into ids).
1227   vtkIdType firstIdx = 0;
1228   vtkVector3d firstPoint;
1229   vtkVector2d firstPointDisplay;
1230   points->GetPoint(ids[firstIdx], firstPoint.GetData());
1231   this->ActorToDisplay(firstPoint, firstPointDisplay);
1232 
1233   // Start of current smooth run (index into ids).
1234   vtkIdType startIdx = 0;
1235   vtkVector3d startPoint;
1236   vtkVector2d startPointDisplay;
1237   points->GetPoint(ids[startIdx], startPoint.GetData());
1238   this->ActorToDisplay(startPoint, startPointDisplay);
1239 
1240   // Accumulated length of segments since startId
1241   std::vector<double> segmentLengths;
1242   double rAccum = 0.;
1243 
1244   // Straight-line distance from start --> previous
1245   double rPrevStraight = 0.;
1246 
1247   // Straight-line distance from start --> current
1248   double rStraight = 0.;
1249 
1250   // Straight-line distance from prev --> current
1251   double rSegment = 0.;
1252 
1253   // Minimum length of a smooth segment in display space
1254   const double minLength = 1.2 * metrics.Dimensions[0];
1255 
1256   // Vector of segment prev --> current
1257   vtkVector2d segment(0, 0);
1258 
1259   // Vector of segment start --> current
1260   vtkVector2d prevStraight(0, 0);
1261   vtkVector2d straight(0, 0);
1262 
1263   // Smoothness of start --> current
1264   double smoothness = 0;
1265 
1266   // Account for skip distance:
1267   while (segment.Norm() < skipDistance)
1268   {
1269     ++startIdx;
1270     points->GetPoint(ids[startIdx], startPoint.GetData());
1271     this->ActorToDisplay(startPoint, startPointDisplay);
1272 
1273     segment = startPointDisplay - firstPointDisplay;
1274   }
1275 
1276   // Find the first visible point
1277   while (startIdx + 1 < numIds && !this->PixelIsVisible(startPointDisplay))
1278   {
1279     ++startIdx;
1280     points->GetPoint(ids[startIdx], startPoint.GetData());
1281     this->ActorToDisplay(startPoint, startPointDisplay);
1282   }
1283 
1284   // Start point in current segment.
1285   vtkVector3d prevPoint = startPoint;
1286   vtkVector2d prevPointDisplay = startPointDisplay;
1287 
1288   // End point of current segment (index into ids).
1289   vtkIdType curIdx = startIdx + 1;
1290   vtkVector3d curPoint = prevPoint;
1291   vtkVector2d curPointDisplay = prevPointDisplay;
1292 
1293   while (curIdx < numIds)
1294   {
1295     // Copy cur --> prev
1296     prevPoint = curPoint;
1297     prevPointDisplay = curPointDisplay;
1298     prevStraight = straight;
1299     rPrevStraight = rStraight;
1300 
1301     // Update current:
1302     points->GetPoint(ids[curIdx], curPoint.GetData());
1303     this->ActorToDisplay(curPoint, curPointDisplay);
1304 
1305     // Calculate lengths and smoothness.
1306     segment = curPointDisplay - prevPointDisplay;
1307     straight = curPointDisplay - startPointDisplay;
1308     rSegment = segment.Norm();
1309     rStraight = straight.Norm();
1310     segmentLengths.push_back(rSegment);
1311     rAccum += rSegment;
1312     smoothness = calculateSmoothness(rAccum, rStraight);
1313 
1314     // Are we still dealing with a reasonably smooth line?
1315     // The first check tests if we've traveled far enough to get a fair estimate
1316     // of smoothness.
1317     if (rAccum < 10. || smoothness <= targetSmoothness)
1318     {
1319       // Advance to the next point:
1320       ++curIdx;
1321       continue;
1322     }
1323     else
1324     {
1325       // The line is no longer smooth "enough". Was start --> previous long
1326       // enough (twice label width)?
1327       if (rPrevStraight >= minLength)
1328       {
1329         // We have a winner!
1330         break;
1331       }
1332       else
1333       {
1334         // This startIdx won't work. On to the next visible startIdx.
1335         do
1336         {
1337           ++startIdx;
1338           points->GetPoint(ids[startIdx], startPoint.GetData());
1339           this->ActorToDisplay(startPoint, startPointDisplay);
1340         }
1341         while (startIdx < numIds && !this->PixelIsVisible(startPointDisplay));
1342 
1343         prevPoint = startPoint;
1344         prevPointDisplay = startPointDisplay;
1345         curPoint = startPoint;
1346         curPointDisplay = startPointDisplay;
1347         curIdx = startIdx + 1;
1348         rAccum = 0.;
1349         rPrevStraight = 0.;
1350         segmentLengths.clear();
1351         continue;
1352       }
1353     }
1354   }
1355 
1356   // Was the last segment ok?
1357   if (rPrevStraight >= minLength)
1358   {
1359     // The final index of the segment:
1360     vtkIdType endIdx = curIdx - 1;
1361 
1362     // The direction of the text.
1363     vtkVector3d prevPointWorld;
1364     vtkVector3d startPointWorld;
1365     this->ActorToWorld(prevPoint, prevPointWorld);
1366     this->ActorToWorld(startPoint, startPointWorld);
1367     info.RightW = (prevPointWorld - startPointWorld).Normalized();
1368     // Ensure the text reads left->right:
1369     if (info.RightW.Dot(this->CameraRight) < 0.)
1370     {
1371       info.RightW = -info.RightW;
1372     }
1373 
1374     // The up vector. Cross the forward direction with the orientation and
1375     // ensure that the result vector is in the same hemisphere as CameraUp
1376     info.UpW = info.RightW.Compare(this->CameraForward, 10e-10)
1377         ? this->CameraUp
1378         : info.RightW.Cross(this->CameraForward).Normalized();
1379     if (info.UpW.Dot(this->CameraUp) < 0.)
1380     {
1381       info.UpW = -info.UpW;
1382     }
1383 
1384     // Walk through the segment lengths to find where the center is for label
1385     // placement:
1386     double targetLength = rPrevStraight * 0.5;
1387     rAccum = 0.;
1388     size_t endIdxOffset = 1;
1389     for (; endIdxOffset <= segmentLengths.size(); ++endIdxOffset)
1390     {
1391       rSegment = segmentLengths[endIdxOffset - 1];
1392       double tmp = rAccum + rSegment;
1393       if (tmp > targetLength)
1394       {
1395         break;
1396       }
1397       rAccum = tmp;
1398     }
1399     targetLength -= rAccum;
1400     points->GetPoint(ids[startIdx + endIdxOffset - 1], prevPoint.GetData());
1401     points->GetPoint(ids[startIdx + endIdxOffset], curPoint.GetData());
1402     vtkVector3d offset = curPoint - prevPoint;
1403     double rSegmentActor = offset.Normalize();
1404     offset = offset * (targetLength * rSegmentActor / rSegment);
1405     info.Position = prevPoint + offset;
1406 
1407     this->ComputeLabelInfo(info, metrics);
1408 
1409     // Update the cell array:
1410     ids += endIdx;
1411     numIds -= endIdx;
1412 
1413     return true;
1414   }
1415 
1416   return false;
1417 }
1418 
1419 //------------------------------------------------------------------------------
BuildLabel(vtkTextActor3D * actor,const LabelMetric & metric,const LabelInfo & info)1420 bool vtkLabeledContourMapper::Private::BuildLabel(vtkTextActor3D *actor,
1421                                                   const LabelMetric &metric,
1422                                                   const LabelInfo &info)
1423 
1424 {
1425   assert(metric.Valid);
1426   actor->SetInput(metric.Text.c_str());
1427   actor->SetTextProperty(metric.TProp);
1428   actor->SetPosition(const_cast<double*>(info.Position.GetData()));
1429 
1430   vtkNew<vtkTransform> xform;
1431   xform->PostMultiply();
1432 
1433   xform->Translate((-info.Position).GetData());
1434 
1435   xform->Scale(info.ScaleDisplayToActor,
1436                info.ScaleDisplayToActor,
1437                info.ScaleDisplayToActor);
1438 
1439   vtkVector3d forward = info.UpA.Cross(info.RightA);
1440   double rot[16];
1441   rot[4 * 0 + 0] = info.RightA[0];
1442   rot[4 * 1 + 0] = info.RightA[1];
1443   rot[4 * 2 + 0] = info.RightA[2];
1444   rot[4 * 3 + 0] = 0;
1445   rot[4 * 0 + 1] = info.UpA[0];
1446   rot[4 * 1 + 1] = info.UpA[1];
1447   rot[4 * 2 + 1] = info.UpA[2];
1448   rot[4 * 3 + 1] = 0;
1449   rot[4 * 0 + 2] = forward[0];
1450   rot[4 * 1 + 2] = forward[1];
1451   rot[4 * 2 + 2] = forward[2];
1452   rot[4 * 3 + 2] = 0;
1453   rot[4 * 0 + 3] = 0;
1454   rot[4 * 1 + 3] = 0;
1455   rot[4 * 2 + 3] = 0;
1456   rot[4 * 3 + 3] = 1;
1457   xform->Concatenate(rot);
1458 
1459   xform->Translate(info.Position.GetData());
1460   actor->SetUserTransform(xform);
1461 
1462   return true;
1463 }
1464 
1465 //------------------------------------------------------------------------------
ComputeLabelInfo(LabelInfo & info,const LabelMetric & metrics)1466 void vtkLabeledContourMapper::Private::ComputeLabelInfo(
1467     LabelInfo &info, const LabelMetric &metrics)
1468 {
1469   // Convert the right and up vectors into actor space:
1470   vtkVector3d worldPosition;
1471   this->ActorToWorld(info.Position, worldPosition);
1472 
1473   vtkVector3d endW = worldPosition + info.RightW;
1474   vtkVector3d endA;
1475   this->WorldToActor(endW, endA);
1476   info.RightA = endA - info.Position;
1477 
1478   endW = worldPosition + info.UpW;
1479   this->WorldToActor(endW, endA);
1480   info.UpA = endA - info.Position;
1481 
1482   // Compute scaling factor. Use the Up vector for deltas as we know it is
1483   // perpendicular to the view axis:
1484   vtkVector3d delta = info.UpA * (0.5 * metrics.Dimensions[0]);
1485   vtkVector3d leftActor = info.Position - delta;
1486   vtkVector3d rightActor = info.Position + delta;
1487   vtkVector2d leftDisplay;
1488   vtkVector2d rightDisplay;
1489   this->ActorToDisplay(leftActor, leftDisplay);
1490   this->ActorToDisplay(rightActor, rightDisplay);
1491   info.ScaleDisplayToActor = static_cast<double>(metrics.Dimensions[0]) /
1492       (rightDisplay - leftDisplay).Norm();
1493 
1494   // Compute the corners of the quad. Actor coordinates are used to create the
1495   // stencil, display coordinates are used to detect collisions.
1496   // Note that we make this a little bigger (4px) than a tight bbox to give a
1497   // little breathing room around the text.
1498   vtkVector3d halfWidth =
1499       ((0.5 * metrics.Dimensions[0] + 2) * info.ScaleDisplayToActor)
1500       * info.RightA;
1501   vtkVector3d halfHeight =
1502       ((0.5 * metrics.Dimensions[1] + 2) * info.ScaleDisplayToActor)
1503       * info.UpA;
1504   info.TLa = info.Position + halfHeight - halfWidth;
1505   info.TRa = info.Position + halfHeight + halfWidth;
1506   info.BRa = info.Position - halfHeight + halfWidth;
1507   info.BLa = info.Position - halfHeight - halfWidth;
1508   this->ActorToDisplay(info.TLa, info.TLd);
1509   this->ActorToDisplay(info.TRa, info.TRd);
1510   this->ActorToDisplay(info.BRa, info.BRd);
1511   this->ActorToDisplay(info.BLa, info.BLd);
1512 }
1513 
1514 // Anonymous namespace for some TestOverlap helpers:
1515 namespace {
1516 
1517 // Rotates the vector by -90 degrees.
perp(vtkVector2i & vec)1518 void perp(vtkVector2i &vec)
1519 {
1520   std::swap(vec[0], vec[1]);
1521   vec[1] = -vec[1];
1522 }
1523 
1524 // Project all points in other onto the line (point + t * direction).
1525 // Return true if t is positive for all points in other (e.g. all points in
1526 // 'other' are outside the polygon containing 'point').
allOutside(const vtkVector2i & point,const vtkVector2i & direction,const LabelInfo & other)1527 bool allOutside(const vtkVector2i &point, const vtkVector2i &direction,
1528                 const LabelInfo &other)
1529 {
1530   vtkVector2i testVector;
1531 
1532   testVector = other.TLd - point;
1533   if (direction.Dot(testVector) <= 0)
1534   {
1535     return false;
1536   }
1537 
1538   testVector = other.TRd - point;
1539   if (direction.Dot(testVector) <= 0)
1540   {
1541     return false;
1542   }
1543 
1544   testVector = other.BRd - point;
1545   if (direction.Dot(testVector) <= 0)
1546   {
1547     return false;
1548   }
1549 
1550   testVector = other.BLd - point;
1551   if (direction.Dot(testVector) <= 0)
1552   {
1553     return false;
1554   }
1555 
1556   return true;
1557 }
1558 
1559 // Generate a vector pointing out from each edge of the rectangle. Do this
1560 // by traversing the corners counter-clockwise and using the perp() function.
1561 // Use allOutside() to determine whether the other polygon is outside the edge.
1562 // Return true if the axis separates the polygons.
testAxis(const LabelInfo & poly,const vtkVector2i & edgeStart,const vtkVector2i & edgeEnd)1563 bool testAxis(const LabelInfo &poly, const vtkVector2i &edgeStart,
1564               const vtkVector2i &edgeEnd)
1565 {
1566   // Vector pointing out of polygon:
1567   vtkVector2i direction = edgeEnd - edgeStart;
1568   perp(direction);
1569 
1570   return allOutside(edgeStart, direction, poly);
1571 }
1572 
1573 } // end anon namespace
1574 
1575 //------------------------------------------------------------------------------
1576 // Implements axis separation method for detecting polygon intersection.
1577 // Ref: http://www.geometrictools.com/Documentation/MethodOfSeparatingAxes.pdf
1578 // In essence, look for an axis that separates the two rectangles.
1579 // Return true if overlap occurs.
TestOverlap(const LabelInfo & a,const LabelInfo & b)1580 bool vtkLabeledContourMapper::Private::TestOverlap(const LabelInfo &a,
1581                                                    const LabelInfo &b)
1582 {
1583   // Note that the order of the points matters, must be CCW to get the correct
1584   // perpendicular vector:
1585   return !(testAxis(a, b.TLd, b.BLd) ||
1586            testAxis(a, b.BLd, b.BRd) ||
1587            testAxis(a, b.BRd, b.TRd) ||
1588            testAxis(a, b.TRd, b.TLd) ||
1589            testAxis(b, a.TLd, a.BLd) ||
1590            testAxis(b, a.BLd, a.BRd) ||
1591            testAxis(b, a.BRd, a.TRd) ||
1592            testAxis(b, a.TRd, a.TLd));
1593 }
1594