1 #include "vtkLabelSizeCalculator.h"
2 
3 #include "vtkCellData.h"
4 #include "vtkDataObject.h"
5 #include "vtkDataSet.h"
6 #include "vtkDataSetAttributes.h"
7 #include "vtkFieldData.h"
8 #include "vtkGraph.h"
9 #include "vtkInformation.h"
10 #include "vtkInformationVector.h"
11 #include "vtkIntArray.h"
12 #include "vtkLabelHierarchy.h"
13 #include "vtkObjectFactory.h"
14 #include "vtkPointData.h"
15 #include "vtkPointSet.h"
16 #include "vtkSmartPointer.h"
17 #include "vtkStringArray.h"
18 #include "vtkTable.h"
19 #include "vtkTextProperty.h"
20 #include "vtkTextRenderer.h"
21 
22 #include <map>
23 
24 class vtkLabelSizeCalculator::Internals
25 {
26 public:
27   std::map<int, vtkSmartPointer<vtkTextProperty> > FontProperties;
28 };
29 
30 vtkStandardNewMacro(vtkLabelSizeCalculator);
31 vtkCxxSetObjectMacro(vtkLabelSizeCalculator,FontUtil,vtkTextRenderer);
32 
vtkLabelSizeCalculator()33 vtkLabelSizeCalculator::vtkLabelSizeCalculator()
34 {
35   this->Implementation = new Internals;
36   // Always defined but user may set to nullptr.
37   this->Implementation->FontProperties[0] = vtkSmartPointer<vtkTextProperty>::New();
38   this->FontUtil = vtkTextRenderer::New(); // Never a nullptr moment.
39   this->LabelSizeArrayName = nullptr;
40   this->SetLabelSizeArrayName( "LabelSize" );
41   this->DPI = 72;
42   this->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "LabelText");
43   this->SetInputArrayToProcess(1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "Type");
44 }
45 
~vtkLabelSizeCalculator()46 vtkLabelSizeCalculator::~vtkLabelSizeCalculator()
47 {
48   this->SetFontUtil( nullptr );
49   this->SetLabelSizeArrayName( nullptr );
50   delete this->Implementation;
51 }
52 
PrintSelf(ostream & os,vtkIndent indent)53 void vtkLabelSizeCalculator::PrintSelf( ostream& os, vtkIndent indent )
54 {
55   this->Superclass::PrintSelf( os, indent );
56   os << indent << "LabelSizeArrayName: " << this->LabelSizeArrayName << "\n";
57   os << indent << "FontProperties: ";
58   std::map<int, vtkSmartPointer<vtkTextProperty> >::iterator it, itEnd;
59   it = this->Implementation->FontProperties.begin();
60   itEnd = this->Implementation->FontProperties.end();
61   for ( ; it != itEnd; ++it )
62   {
63     os << indent << "  " << it->first << ": " << it->second << endl;
64   }
65   os << indent << "FontUtil: " << this->FontUtil << "\n";
66 }
67 
FillInputPortInformation(int vtkNotUsed (port),vtkInformation * info)68 int vtkLabelSizeCalculator::FillInputPortInformation( int vtkNotUsed(port), vtkInformation* info )
69 {
70   info->Remove( vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE() );
71   info->Append( vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet" );
72   info->Append( vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGraph" );
73   return 1;
74 }
75 
SetFontProperty(vtkTextProperty * prop,int type)76 void vtkLabelSizeCalculator::SetFontProperty(vtkTextProperty* prop, int type)
77 {
78   this->Implementation->FontProperties[type] = prop;
79 }
80 
GetFontProperty(int type)81 vtkTextProperty* vtkLabelSizeCalculator::GetFontProperty(int type)
82 {
83   if (this->Implementation->FontProperties.find(type) !=
84       this->Implementation->FontProperties.end())
85   {
86     return this->Implementation->FontProperties[type];
87   }
88   return nullptr;
89 }
90 
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)91 int vtkLabelSizeCalculator::RequestData(
92   vtkInformation* vtkNotUsed(request),
93   vtkInformationVector** inputVector,
94   vtkInformationVector* outputVector )
95 {
96   // get the info objects
97   vtkInformation* inInfo = inputVector[0]->GetInformationObject( 0 );
98   vtkInformation* outInfo = outputVector->GetInformationObject( 0 );
99 
100   // get the input and output
101   vtkDataObject* input = inInfo->Get( vtkDataObject::DATA_OBJECT() );
102   vtkDataObject* output = outInfo->Get( vtkDataObject::DATA_OBJECT() );
103 
104   vtkFieldData* inFD = nullptr;
105   vtkFieldData* outFD = nullptr;
106 
107   vtkDataSet* dsInput = vtkDataSet::SafeDownCast( input );
108   vtkDataSet* dsOutput = vtkDataSet::SafeDownCast( output );
109   vtkGraph* graphInput = vtkGraph::SafeDownCast( input );
110   vtkGraph* graphOutput = vtkGraph::SafeDownCast( output );
111 
112   // if input is empty, we are done
113   if (graphInput && graphInput->GetNumberOfVertices() == 0)
114   {
115     return 1;
116   }
117   if (dsInput && dsInput->GetNumberOfPoints() == 0)
118   {
119     return 1;
120   }
121 
122   if ( ! this->Implementation->FontProperties[0] )
123   {
124     vtkErrorMacro( "nullptr default font property, so I cannot compute label sizes." );
125     return 0;
126   }
127 
128   if ( ! this->LabelSizeArrayName )
129   {
130     vtkErrorMacro( "nullptr value for LabelSizeArrayName." );
131     return 0;
132   }
133 
134   // Figure out which array to process
135   vtkAbstractArray* inArr = this->GetInputAbstractArrayToProcess( 0, inputVector );
136   if ( ! inArr )
137   {
138     vtkErrorMacro( "No input array available." );
139     return 0;
140   }
141   vtkIntArray* typeArr = vtkArrayDownCast<vtkIntArray>(
142     this->GetInputAbstractArrayToProcess( 1, inputVector ));
143 
144   vtkInformation* inArrInfo = this->GetInputArrayInformation( 0 );
145   int fieldAssoc = inArrInfo->Get( vtkDataObject::FIELD_ASSOCIATION() );
146 
147   vtkIntArray* lsz = this->LabelSizesForArray( inArr, typeArr );
148 #if 0
149   cout
150     << "Input array... port: " << port << " connection: " << connection
151     << " field association: " << fieldAssoc << " attribute type: " << attribType << "\n";
152 #endif // 0
153 
154   if ( dsInput )
155   {
156     dsOutput->CopyStructure( dsInput );
157     dsOutput->CopyAttributes( dsInput );
158     if (
159       fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_NONE ||
160       fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_POINTS ||
161       fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_POINTS_THEN_CELLS ||
162       fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_VERTICES ||
163       fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_NONE )
164     {
165       outFD = dsOutput->GetPointData();
166       outFD->AddArray( lsz );
167     }
168     if (
169       ! inFD && (
170         fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_POINTS_THEN_CELLS ||
171         fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_CELLS ||
172         fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_EDGES
173       ) )
174     {
175       outFD = dsOutput->GetCellData();
176       outFD->AddArray( lsz );
177     }
178     vtkLabelHierarchy* hierarchyOutput = vtkLabelHierarchy::SafeDownCast( output );
179     if ( hierarchyOutput )
180     {
181       hierarchyOutput->SetSizes( lsz );
182     }
183   }
184   else if ( graphInput )
185   {
186     graphOutput->ShallowCopy( graphInput );
187     if (
188       fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_NONE ||
189       fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_POINTS ||
190       fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_POINTS_THEN_CELLS ||
191       fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_VERTICES ||
192       fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_NONE )
193     {
194       outFD = graphOutput->GetVertexData();
195       outFD->AddArray( lsz );
196     }
197     if (
198       ! inFD && (
199         fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_POINTS_THEN_CELLS ||
200         fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_CELLS ||
201         fieldAssoc == vtkDataObject::FIELD_ASSOCIATION_EDGES
202       ) )
203     {
204       outFD = graphOutput->GetEdgeData();
205       outFD->AddArray( lsz );
206     }
207   }
208   lsz->Delete();
209 
210   return 1;
211 }
212 
LabelSizesForArray(vtkAbstractArray * labels,vtkIntArray * types)213 vtkIntArray* vtkLabelSizeCalculator::LabelSizesForArray(
214   vtkAbstractArray* labels,
215   vtkIntArray* types )
216 {
217   vtkIdType nl = labels->GetNumberOfTuples();
218 
219   vtkIntArray* lsz = vtkIntArray::New();
220   lsz->SetName( this->LabelSizeArrayName );
221   lsz->SetNumberOfComponents( 4 );
222   lsz->SetNumberOfTuples( nl );
223 
224   int bbox[4];
225   int* bds = lsz->GetPointer( 0 );
226   for ( vtkIdType i = 0; i < nl; ++ i )
227   {
228     int type = 0;
229     if ( types )
230     {
231       type = types->GetValue( i );
232     }
233     vtkTextProperty* prop = this->Implementation->FontProperties[type];
234     if (!prop)
235     {
236       prop = this->Implementation->FontProperties[0];
237     }
238     this->FontUtil->GetBoundingBox(
239           prop, labels->GetVariantValue(i).ToString().c_str(), bbox, this->DPI);
240     bds[0] = bbox[1] - bbox[0];
241     bds[1] = bbox[3] - bbox[2];
242     bds[2] = bbox[0];
243     bds[3] = bbox[2];
244 
245     if( this->GetDebug() )
246     {
247       cout << "LSC: "
248            << bds[0] << " " << bds[1] << " " << bds[2] << " " << bds[3]
249            << " \"" << labels->GetVariantValue( i ).ToString().c_str() << "\"\n";
250     }
251 
252     bds += 4;
253   }
254 
255   return lsz;
256 }
257 
258