1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    TestDiagram.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 "vtkGraphItem.h"
16 
17 #include "vtkBrush.h"
18 #include "vtkCallbackCommand.h"
19 #include "vtkContext2D.h"
20 #include "vtkContextMouseEvent.h"
21 #include "vtkContextScene.h"
22 #include "vtkGraph.h"
23 #include "vtkImageData.h"
24 #include "vtkIncrementalForceLayout.h"
25 #include "vtkMarkerUtilities.h"
26 #include "vtkObjectFactory.h"
27 #include "vtkPen.h"
28 #include "vtkPoints.h"
29 #include "vtkRenderWindowInteractor.h"
30 #include "vtkTooltipItem.h"
31 #include "vtkTransform2D.h"
32 #include "vtkVectorOperators.h"
33 
34 #include <vector>
35 
36 vtkStandardNewMacro(vtkGraphItem);
37 vtkCxxSetObjectMacro(vtkGraphItem, Graph, vtkGraph);
38 
39 struct vtkGraphItem::Internals {
40   std::vector<float> VertexSizes;
41   std::vector<vtkVector2f> VertexPositions;
42   std::vector<vtkColor4ub> VertexColors;
43   std::vector<int> VertexMarkers;
44 
45   std::vector<std::vector<vtkVector2f> > EdgePositions;
46   std::vector<std::vector<vtkColor4ub> > EdgeColors;
47   std::vector<float> EdgeWidths;
48 
49   bool Animating;
50   bool AnimationCallbackInitialized;
51   vtkRenderWindowInteractor *Interactor;
52   vtkNew<vtkCallbackCommand> AnimationCallback;
53   int TimerId;
54   bool GravityPointSet;
55 
56   float CurrentScale[2];
57   vtkVector2f LastMousePos;
58 
59   float LayoutAlphaStart;
60   float LayoutAlphaCoolDown;
61   float LayoutAlphaStop;
62 };
63 
vtkGraphItem()64 vtkGraphItem::vtkGraphItem()
65 {
66   this->Graph = 0;
67   this->GraphBuildTime = 0;
68   this->Internal = new Internals();
69   this->Internal->Interactor = NULL;
70   this->Internal->Animating = false;
71   this->Internal->AnimationCallbackInitialized = false;
72   this->Internal->TimerId = 0;
73   this->Internal->CurrentScale[0] = 1.0f;
74   this->Internal->CurrentScale[1] = 1.0f;
75   this->Internal->LastMousePos = vtkVector2f(0, 0);
76   this->Internal->LayoutAlphaStart = 0.1f;
77   this->Internal->LayoutAlphaCoolDown = 0.99f;
78   this->Internal->LayoutAlphaStop = 0.005f;
79   this->Internal->GravityPointSet = false;
80   this->Tooltip->SetVisible(false);
81   this->AddItem(this->Tooltip.GetPointer());
82 }
83 
~vtkGraphItem()84 vtkGraphItem::~vtkGraphItem()
85 {
86   if (this->Internal->Animating)
87     {
88     this->StopLayoutAnimation();
89     }
90   if (this->Internal->AnimationCallbackInitialized)
91     {
92     this->Internal->Interactor->RemoveObserver(this->Internal->AnimationCallback.GetPointer());
93     }
94   delete this->Internal;
95   if (this->Graph)
96     {
97     this->Graph->Delete();
98     }
99 }
100 
GetLayout()101 vtkIncrementalForceLayout *vtkGraphItem::GetLayout()
102 {
103   return this->Layout.GetPointer();
104 }
105 
VertexColor(vtkIdType vtkNotUsed (item))106 vtkColor4ub vtkGraphItem::VertexColor(vtkIdType vtkNotUsed(item))
107 {
108   return vtkColor4ub(128, 128, 128, 255);
109 }
110 
VertexPosition(vtkIdType item)111 vtkVector2f vtkGraphItem::VertexPosition(vtkIdType item)
112 {
113   double *p = this->Graph->GetPoints()->GetPoint(item);
114   return vtkVector2f(static_cast<float>(p[0]), static_cast<float>(p[1]));
115 }
116 
VertexSize(vtkIdType vtkNotUsed (item))117 float vtkGraphItem::VertexSize(vtkIdType vtkNotUsed(item))
118 {
119   return 10.0f;
120 }
121 
VertexMarker(vtkIdType vtkNotUsed (item))122 int vtkGraphItem::VertexMarker(vtkIdType vtkNotUsed(item))
123 {
124   return vtkMarkerUtilities::CIRCLE;
125 }
126 
VertexTooltip(vtkIdType vtkNotUsed (item))127 vtkStdString vtkGraphItem::VertexTooltip(vtkIdType vtkNotUsed(item))
128 {
129   return "";
130 }
131 
EdgeColor(vtkIdType vtkNotUsed (edgeIdx),vtkIdType vtkNotUsed (point))132 vtkColor4ub vtkGraphItem::EdgeColor(vtkIdType vtkNotUsed(edgeIdx), vtkIdType vtkNotUsed(point))
133 {
134   return vtkColor4ub(0, 0, 0, 255);
135 }
136 
EdgePosition(vtkIdType edgeIdx,vtkIdType point)137 vtkVector2f vtkGraphItem::EdgePosition(vtkIdType edgeIdx, vtkIdType point)
138 {
139   double *p;
140   if (point == 0)
141     {
142     vtkPoints *points = this->Graph->GetPoints();
143     p = points->GetPoint(this->Graph->GetSourceVertex(edgeIdx));
144     }
145   else if (point == this->NumberOfEdgePoints(edgeIdx) - 1)
146     {
147     vtkPoints *points = this->Graph->GetPoints();
148     p = points->GetPoint(this->Graph->GetTargetVertex(edgeIdx));
149     }
150   else
151     {
152     p = this->Graph->GetEdgePoint(edgeIdx, point - 1);
153     }
154   return vtkVector2f(static_cast<float>(p[0]), static_cast<float>(p[1]));
155 }
156 
EdgeWidth(vtkIdType vtkNotUsed (line),vtkIdType vtkNotUsed (point))157 float vtkGraphItem::EdgeWidth(vtkIdType vtkNotUsed(line), vtkIdType vtkNotUsed(point))
158 {
159   return 0.0f;
160 }
161 
RebuildBuffers()162 void vtkGraphItem::RebuildBuffers()
163 {
164   vtkIdType numEdges = this->NumberOfEdges();
165   this->Internal->EdgePositions = std::vector<std::vector<vtkVector2f> >(numEdges);
166   this->Internal->EdgeColors = std::vector<std::vector<vtkColor4ub> >(numEdges);
167   this->Internal->EdgeWidths = std::vector<float>(numEdges);
168   for (vtkIdType edgeIdx = 0; edgeIdx < numEdges; ++edgeIdx)
169     {
170     vtkIdType numPoints = this->NumberOfEdgePoints(edgeIdx);
171     this->Internal->EdgePositions[edgeIdx] = std::vector<vtkVector2f>(numPoints);
172     this->Internal->EdgeColors[edgeIdx] = std::vector<vtkColor4ub>(numPoints);
173     this->Internal->EdgeWidths[edgeIdx] = this->EdgeWidth(edgeIdx, 0);
174     for (vtkIdType pointIdx = 0; pointIdx < numPoints; ++pointIdx)
175       {
176       this->Internal->EdgePositions[edgeIdx][pointIdx] = this->EdgePosition(edgeIdx, pointIdx);
177       this->Internal->EdgeColors[edgeIdx][pointIdx] = this->EdgeColor(edgeIdx, pointIdx);
178       }
179     }
180 
181   vtkIdType numVertices = this->NumberOfVertices();
182   this->Internal->VertexPositions = std::vector<vtkVector2f>(numVertices);
183   this->Internal->VertexColors = std::vector<vtkColor4ub>(numVertices);
184   this->Internal->VertexSizes = std::vector<float>(numVertices);
185   this->Internal->VertexMarkers = std::vector<int>(numVertices);
186   vtkMarkerUtilities::GenerateMarker(this->Sprite.GetPointer(), this->VertexMarker(0), static_cast<int>(this->VertexSize(0)));
187   for (vtkIdType vertexIdx = 0; vertexIdx < numVertices; ++vertexIdx)
188     {
189     this->Internal->VertexPositions[vertexIdx] = this->VertexPosition(vertexIdx);
190     this->Internal->VertexColors[vertexIdx] = this->VertexColor(vertexIdx);
191     this->Internal->VertexSizes[vertexIdx] = this->VertexSize(vertexIdx);
192     this->Internal->VertexMarkers[vertexIdx] = this->VertexMarker(vertexIdx);
193     }
194 }
195 
PaintBuffers(vtkContext2D * painter)196 void vtkGraphItem::PaintBuffers(vtkContext2D *painter)
197 {
198   if (this->Internal->EdgePositions.empty())
199     {
200     return;
201     }
202   vtkIdType numEdges = this->Internal->EdgePositions.size();
203   for (vtkIdType edgeIdx = 0; edgeIdx < numEdges; ++edgeIdx)
204     {
205     if (this->Internal->EdgePositions[edgeIdx].empty())
206       {
207       continue;
208       }
209     painter->GetPen()->SetWidth(this->Internal->EdgeWidths[edgeIdx]);
210     painter->DrawPoly(this->Internal->EdgePositions[edgeIdx][0].GetData(),
211                       static_cast<int>(this->Internal->EdgePositions[edgeIdx].size()),
212                       this->Internal->EdgeColors[edgeIdx][0].GetData(), 4);
213     }
214 
215   if (this->Internal->VertexPositions.empty())
216     {
217     return;
218     }
219   painter->GetPen()->SetWidth(this->Internal->VertexSizes[0]);
220   painter->GetBrush()->SetTextureProperties(vtkBrush::Linear);
221   painter->DrawPointSprites(this->Sprite.GetPointer(),
222                             this->Internal->VertexPositions[0].GetData(),
223                             static_cast<int>(this->Internal->VertexPositions.size()),
224                             this->Internal->VertexColors[0].GetData(), 4);
225 }
226 
NumberOfVertices()227 vtkIdType vtkGraphItem::NumberOfVertices()
228 {
229   if (!this->Graph)
230     {
231     return 0;
232     }
233   return this->Graph->GetNumberOfVertices();
234 }
235 
NumberOfEdges()236 vtkIdType vtkGraphItem::NumberOfEdges()
237 {
238   if (!this->Graph)
239     {
240     return 0;
241     }
242   return this->Graph->GetNumberOfEdges();
243 }
244 
NumberOfEdgePoints(vtkIdType edgeIdx)245 vtkIdType vtkGraphItem::NumberOfEdgePoints(vtkIdType edgeIdx)
246 {
247   if (!this->Graph)
248     {
249     return 0;
250     }
251   return this->Graph->GetNumberOfEdgePoints(edgeIdx) + 2;
252 }
253 
IsDirty()254 bool vtkGraphItem::IsDirty()
255 {
256   if (!this->Graph)
257     {
258     return false;
259     }
260   if (this->Graph->GetMTime() > this->GraphBuildTime)
261     {
262     this->GraphBuildTime = this->Graph->GetMTime();
263     return true;
264     }
265   return false;
266 }
267 
Paint(vtkContext2D * painter)268 bool vtkGraphItem::Paint(vtkContext2D *painter)
269 {
270   if (this->IsDirty())
271     {
272     this->RebuildBuffers();
273     }
274   this->PaintBuffers(painter);
275   this->PaintChildren(painter);
276 
277   // Keep the current scale so we can use it in event handlers.
278   painter->GetTransform()->GetScale(this->Internal->CurrentScale);
279 
280   return true;
281 }
282 
ProcessEvents(vtkObject * vtkNotUsed (caller),unsigned long event,void * clientData,void * callerData)283 void vtkGraphItem::ProcessEvents(vtkObject *vtkNotUsed(caller), unsigned long event,
284                                  void *clientData, void *callerData)
285 {
286   vtkGraphItem *self =
287       reinterpret_cast<vtkGraphItem *>(clientData);
288   switch (event)
289     {
290     case vtkCommand::TimerEvent:
291       {
292       // We must filter the events to ensure we actually get the timer event we
293       // created. I would love signals and slots...
294       int timerId = *static_cast<int *>(callerData);   // Seems to work.
295       if (self->Internal->Animating &&
296           timerId == static_cast<int>(self->Internal->TimerId))
297         {
298         self->UpdateLayout();
299         vtkIdType v = self->HitVertex(self->Internal->LastMousePos);
300         self->PlaceTooltip(v);
301         self->GetScene()->SetDirty(true);
302         }
303       break;
304       }
305     default:
306       break;
307     }
308 }
309 
StartLayoutAnimation(vtkRenderWindowInteractor * interactor)310 void vtkGraphItem::StartLayoutAnimation(vtkRenderWindowInteractor *interactor)
311 {
312   // Start a simple repeating timer
313   if (!this->Internal->Animating && interactor)
314     {
315     if (!this->Internal->AnimationCallbackInitialized)
316       {
317       this->Internal->AnimationCallback->SetClientData(this);
318       this->Internal->AnimationCallback->SetCallback(vtkGraphItem::ProcessEvents);
319       interactor->AddObserver(vtkCommand::TimerEvent,
320                               this->Internal->AnimationCallback.GetPointer(),
321                               0);
322       this->Internal->Interactor = interactor;
323       this->Internal->AnimationCallbackInitialized = true;
324       }
325     this->Internal->Animating = true;
326     // This defines the interval at which the animation will proceed. 60Hz?
327     this->Internal->TimerId = interactor->CreateRepeatingTimer(1000 / 60);
328     if (!this->Internal->GravityPointSet)
329       {
330       vtkVector2f screenPos(this->Scene->GetSceneWidth()/2.0f, this->Scene->GetSceneHeight()/2.0f);
331       vtkVector2f pos = this->MapFromScene(screenPos);
332       this->Layout->SetGravityPoint(pos);
333       this->Internal->GravityPointSet = true;
334       }
335     this->Layout->SetAlpha(this->Internal->LayoutAlphaStart);
336     }
337 }
338 
StopLayoutAnimation()339 void vtkGraphItem::StopLayoutAnimation()
340 {
341   this->Internal->Interactor->DestroyTimer(this->Internal->TimerId);
342   this->Internal->TimerId = 0;
343   this->Internal->Animating = false;
344 }
345 
UpdateLayout()346 void vtkGraphItem::UpdateLayout()
347 {
348   if (this->Graph)
349     {
350     this->Layout->SetGraph(this->Graph);
351     this->Layout->SetAlpha(this->Layout->GetAlpha()*this->Internal->LayoutAlphaCoolDown);
352     this->Layout->UpdatePositions();
353     this->Graph->Modified();
354     if (this->Internal->Animating && this->Layout->GetAlpha() < this->Internal->LayoutAlphaStop)
355       {
356       this->StopLayoutAnimation();
357       }
358     }
359 }
360 
HitVertex(const vtkVector2f & pos)361 vtkIdType vtkGraphItem::HitVertex(const vtkVector2f &pos)
362 {
363   vtkIdType numVert = static_cast<vtkIdType>(this->Internal->VertexPositions.size());
364   for (vtkIdType v = 0; v < numVert; ++v)
365     {
366     if ((pos - this->Internal->VertexPositions[v]).Norm() < this->Internal->VertexSizes[v]/this->Internal->CurrentScale[0]/2.0)
367       {
368       return v;
369       }
370     }
371   return -1;
372 }
373 
MouseMoveEvent(const vtkContextMouseEvent & event)374 bool vtkGraphItem::MouseMoveEvent(const vtkContextMouseEvent &event)
375 {
376   this->Internal->LastMousePos = event.GetPos();
377   if (event.GetButton() == vtkContextMouseEvent::NO_BUTTON)
378     {
379     vtkIdType v = this->HitVertex(event.GetPos());
380     this->Scene->SetDirty(true);
381     if (v < 0)
382       {
383       this->Tooltip->SetVisible(false);
384       return true;
385       }
386     vtkStdString text = this->VertexTooltip(v);
387     if (text == "")
388       {
389       this->Tooltip->SetVisible(false);
390       return true;
391       }
392     this->PlaceTooltip(v);
393     this->Tooltip->SetText(text);
394     this->Tooltip->SetVisible(true);
395     return true;
396     }
397   if (event.GetButton() == vtkContextMouseEvent::LEFT_BUTTON)
398     {
399     if (this->Layout->GetFixed() >= 0)
400       {
401       this->Layout->SetAlpha(this->Internal->LayoutAlphaStart);
402       this->Graph->GetPoints()->SetPoint(this->Layout->GetFixed(), event.GetPos()[0], event.GetPos()[1], 0.0);
403       }
404     return true;
405     }
406 
407   if (this->Tooltip->GetVisible())
408     {
409     vtkIdType v = this->HitVertex(event.GetPos());
410     this->PlaceTooltip(v);
411     this->Scene->SetDirty(true);
412     }
413 
414   return false;
415 }
416 
MouseEnterEvent(const vtkContextMouseEvent & vtkNotUsed (event))417 bool vtkGraphItem::MouseEnterEvent(const vtkContextMouseEvent &vtkNotUsed(event))
418 {
419   return true;
420 }
421 
MouseLeaveEvent(const vtkContextMouseEvent & vtkNotUsed (event))422 bool vtkGraphItem::MouseLeaveEvent(const vtkContextMouseEvent &vtkNotUsed(event))
423 {
424   this->Tooltip->SetVisible(false);
425   return true;
426 }
427 
MouseButtonPressEvent(const vtkContextMouseEvent & event)428 bool vtkGraphItem::MouseButtonPressEvent(const vtkContextMouseEvent &event)
429 {
430   this->Tooltip->SetVisible(false);
431   if (event.GetButton() == vtkContextMouseEvent::LEFT_BUTTON)
432     {
433     vtkIdType hitVertex = this->HitVertex(event.GetPos());
434     this->Layout->SetFixed(hitVertex);
435     if (hitVertex >= 0 && this->Internal->Interactor)
436       {
437       this->Layout->SetAlpha(this->Internal->LayoutAlphaStart);
438       if (!this->Internal->Animating && this->Internal->Interactor)
439         {
440         this->StartLayoutAnimation(this->Internal->Interactor);
441         }
442       }
443     return true;
444     }
445   return false;
446 }
447 
MouseButtonReleaseEvent(const vtkContextMouseEvent & event)448 bool vtkGraphItem::MouseButtonReleaseEvent(const vtkContextMouseEvent &event)
449 {
450   if (event.GetButton() == vtkContextMouseEvent::LEFT_BUTTON)
451     {
452     this->Layout->SetFixed(-1);
453     return true;
454     }
455   return false;
456 }
457 
MouseWheelEvent(const vtkContextMouseEvent & event,int vtkNotUsed (delta))458 bool vtkGraphItem::MouseWheelEvent(const vtkContextMouseEvent &event, int vtkNotUsed(delta))
459 {
460   if (this->Tooltip->GetVisible())
461     {
462     vtkIdType v = this->HitVertex(event.GetPos());
463     this->PlaceTooltip(v);
464     this->Scene->SetDirty(true);
465     }
466 
467   return false;
468 }
469 
Hit(const vtkContextMouseEvent & event)470 bool vtkGraphItem::Hit(const vtkContextMouseEvent &event)
471 {
472   vtkIdType v = this->HitVertex(event.GetPos());
473   return (v >= 0);
474 }
475 
PlaceTooltip(vtkIdType v)476 void vtkGraphItem::PlaceTooltip(vtkIdType v)
477 {
478   if (v >= 0)
479     {
480     vtkVector2f pos = this->Internal->VertexPositions[v];
481     this->Tooltip->SetPosition(
482           pos[0] + 5/this->Internal->CurrentScale[0],
483           pos[1] + 5/this->Internal->CurrentScale[1]);
484     }
485   else
486     {
487     this->Tooltip->SetVisible(false);
488     }
489 }
490 
PrintSelf(ostream & os,vtkIndent indent)491 void vtkGraphItem::PrintSelf(ostream &os, vtkIndent indent)
492 {
493   this->Superclass::PrintSelf(os, indent);
494   os << "Graph: " << (this->Graph ? "" : "(null)") << std::endl;
495   if (this->Graph)
496     {
497     this->Graph->PrintSelf(os, indent.GetNextIndent());
498     }
499   os << "GraphBuildTime: " << this->GraphBuildTime << std::endl;
500 }
501