1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkBiDimensionalRepresentation2D.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 "vtkBiDimensionalRepresentation2D.h"
16 #include "vtkHandleRepresentation.h"
17 #include "vtkCoordinate.h"
18 #include "vtkRenderer.h"
19 #include "vtkMath.h"
20 #include "vtkLine.h"
21 #include "vtkTextProperty.h"
22 #include "vtkWindow.h"
23 #include "vtkCellArray.h"
24 #include "vtkPoints.h"
25 #include "vtkPolyData.h"
26 #include "vtkPolyDataMapper2D.h"
27 #include "vtkActor2D.h"
28 #include "vtkTextMapper.h"
29 #include "vtkTextProperty.h"
30 #include "vtkProperty2D.h"
31 #include "vtkPointHandleRepresentation2D.h"
32 #include "vtkObjectFactory.h"
33 #include "vtkInteractorObserver.h"
34 
35 #include <sstream>
36 
37 vtkStandardNewMacro(vtkBiDimensionalRepresentation2D);
38 
39 
40 //----------------------------------------------------------------------
vtkBiDimensionalRepresentation2D()41 vtkBiDimensionalRepresentation2D::vtkBiDimensionalRepresentation2D() : vtkBiDimensionalRepresentation()
42 {
43   // Create the geometry for the two axes
44   this->LineCells = vtkCellArray::New();
45   this->LineCells->InsertNextCell(2);
46   this->LineCells->InsertCellPoint(0);
47   this->LineCells->InsertCellPoint(1);
48   this->LineCells->InsertNextCell(2);
49   this->LineCells->InsertCellPoint(2);
50   this->LineCells->InsertCellPoint(3);
51   this->LinePoints = vtkPoints::New();
52   this->LinePoints->SetNumberOfPoints(4);
53   this->LinePolyData = vtkPolyData::New();
54   this->LinePolyData->SetPoints(this->LinePoints);
55   this->LinePolyData->SetLines(this->LineCells);
56   this->LineMapper = vtkPolyDataMapper2D::New();
57   this->LineMapper->SetInputData(this->LinePolyData);
58   this->LineProperty = vtkProperty2D::New();
59   this->LineActor = vtkActor2D::New();
60   this->LineActor->SetProperty(this->LineProperty);
61   this->LineActor->SetMapper(this->LineMapper);
62   this->SelectedLineProperty = vtkProperty2D::New();
63   this->SelectedLineProperty->SetColor(0.0,1.0,0.0);
64   this->SelectedLineProperty->SetLineWidth(2.0);
65 
66   this->TextProperty = vtkTextProperty::New();
67   this->TextProperty->SetBold(1);
68   this->TextProperty->SetItalic(1);
69   this->TextProperty->SetShadow(1);
70   this->TextProperty->SetFontFamilyToArial();
71   this->TextMapper = vtkTextMapper::New();
72   this->TextMapper->SetTextProperty(this->TextProperty);
73   this->TextMapper->SetInput("0.0");
74   this->TextActor = vtkActor2D::New();
75   this->TextActor->SetMapper(this->TextMapper);
76 }
77 
78 //----------------------------------------------------------------------
~vtkBiDimensionalRepresentation2D()79 vtkBiDimensionalRepresentation2D::~vtkBiDimensionalRepresentation2D()
80 {
81   this->LineCells->Delete();
82   this->LinePoints->Delete();
83   this->LinePolyData->Delete();
84   this->LineMapper->Delete();
85   this->LineProperty->Delete();
86   this->LineActor->Delete();
87   this->SelectedLineProperty->Delete();
88   this->TextProperty->Delete();
89   this->TextMapper->Delete();
90   this->TextActor->Delete();
91 }
92 
93 
94 //----------------------------------------------------------------------
95 int vtkBiDimensionalRepresentation2D::
ComputeInteractionState(int X,int Y,int modify)96 ComputeInteractionState(int X, int Y, int modify)
97 {
98   this->Modifier = modify;
99 
100   // Check if we are on end points. The handles must tell us to ensure
101   // consistent state.
102   int p1State = this->Point1Representation->ComputeInteractionState(X,Y,0);
103   int p2State = this->Point2Representation->ComputeInteractionState(X,Y,0);
104   int p3State = this->Point3Representation->ComputeInteractionState(X,Y,0);
105   int p4State = this->Point4Representation->ComputeInteractionState(X,Y,0);
106   if ( p1State == vtkHandleRepresentation::Nearby )
107   {
108     this->InteractionState = vtkBiDimensionalRepresentation2D::NearP1;
109   }
110   else if ( p2State == vtkHandleRepresentation::Nearby )
111   {
112     this->InteractionState = vtkBiDimensionalRepresentation2D::NearP2;
113   }
114   else if ( p3State == vtkHandleRepresentation::Nearby )
115   {
116     this->InteractionState = vtkBiDimensionalRepresentation2D::NearP3;
117   }
118   else if ( p4State == vtkHandleRepresentation::Nearby )
119   {
120     this->InteractionState = vtkBiDimensionalRepresentation2D::NearP4;
121   }
122   else
123   {
124     this->InteractionState = vtkBiDimensionalRepresentation2D::Outside;
125   }
126 
127   // Okay if we're near a handle return, otherwise test edges.
128   if ( this->InteractionState != vtkBiDimensionalRepresentation2D::Outside )
129   {
130     return this->InteractionState;
131   }
132 
133   // See if we are near the edges. Requires separate computation.
134   double pos1[3], pos2[3], pos3[3], pos4[3];
135   this->GetPoint1DisplayPosition(pos1);
136   this->GetPoint2DisplayPosition(pos2);
137   this->GetPoint3DisplayPosition(pos3);
138   this->GetPoint4DisplayPosition(pos4);
139 
140   double p1[3], p2[3], p3[3], p4[3], xyz[3];
141   double t, closest[3];
142   xyz[0] = static_cast<double>(X);
143   xyz[1] = static_cast<double>(Y);
144   p1[0] = static_cast<double>(pos1[0]);
145   p1[1] = static_cast<double>(pos1[1]);
146   p2[0] = static_cast<double>(pos2[0]);
147   p2[1] = static_cast<double>(pos2[1]);
148   p3[0] = static_cast<double>(pos3[0]);
149   p3[1] = static_cast<double>(pos3[1]);
150   p4[0] = static_cast<double>(pos4[0]);
151   p4[1] = static_cast<double>(pos4[1]);
152   xyz[2] = p1[2] = p2[2] = p3[2] = p4[2] = 0.0;
153 
154   double tol2 = this->Tolerance*this->Tolerance;
155 
156   // Compute intersection point.
157   double uIntersect, vIntersect;
158   vtkLine::Intersection(p1, p2, p3, p4, uIntersect, vIntersect);
159 
160   // Check if we are on edges
161   int onL1 = (vtkLine::DistanceToLine(xyz,p1,p2,t,closest) <= tol2);
162   int onL2 = (vtkLine::DistanceToLine(xyz,p3,p4,t,closest) <= tol2);
163 
164   double xyzParam;
165 
166   if ( onL1 && onL2 )
167   {
168     this->InteractionState = vtkBiDimensionalRepresentation2D::OnCenter;
169   }
170   else if ( onL1 )
171   {
172     if (p1[0] != p2[0])
173     {
174       xyzParam = (xyz[0] - p1[0]) / (p2[0] - p1[0]);
175       if (xyzParam < uIntersect)
176       {
177         // closer to p1
178         if (xyzParam < (uIntersect*0.5))
179         {
180           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL1Outer;
181         }
182         else
183         {
184           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL1Inner;
185         }
186       }
187       else
188       {
189         // closer to p2
190         if (xyzParam > ((1+uIntersect)*0.5))
191         {
192           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL1Outer;
193         }
194         else
195         {
196           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL1Inner;
197         }
198       }
199     }
200     else
201     {
202       xyzParam = (xyz[1] - p1[1]) / (p2[1] - p1[1]);
203       if (xyzParam < uIntersect)
204       {
205         // closer to p1
206         if (xyzParam < (uIntersect*0.5))
207         {
208           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL1Outer;
209         }
210         else
211         {
212           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL1Inner;
213         }
214       }
215       else
216       {
217         // closer to p2
218         if (xyzParam > ((1+uIntersect)*0.5))
219         {
220           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL1Outer;
221         }
222         else
223         {
224           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL1Inner;
225         }
226       }
227     }
228   }
229   else if ( onL2 )
230   {
231     if (p3[0] != p4[0])
232     {
233       xyzParam = (xyz[0] - p3[0]) / (p4[0] - p3[0]);
234       if (xyzParam < vIntersect)
235       {
236         // closer to p3
237         if (xyzParam < (vIntersect*0.5))
238         {
239           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL2Outer;
240         }
241         else
242         {
243           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL2Inner;
244         }
245       }
246       else
247       {
248         // closer to p4
249         if (xyzParam > ((1+vIntersect)*0.5))
250         {
251           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL2Outer;
252         }
253         else
254         {
255           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL2Inner;
256         }
257       }
258     }
259     else
260     {
261       xyzParam = (xyz[1] - p3[1]) / (p4[1] - p3[1]);
262       if (xyzParam < vIntersect)
263       {
264         // closer to p3
265         if (xyzParam < (vIntersect*0.5))
266         {
267           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL2Outer;
268         }
269         else
270         {
271           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL2Inner;
272         }
273       }
274       else
275       {
276         // closer to p4
277         if (xyzParam > ((1+vIntersect)*0.5))
278         {
279           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL2Outer;
280         }
281         else
282         {
283           this->InteractionState = vtkBiDimensionalRepresentation2D::OnL2Inner;
284         }
285       }
286     }
287   }
288   else
289   {
290     this->InteractionState = vtkBiDimensionalRepresentation2D::Outside;
291     this->Modifier = 0;
292   }
293 
294   return this->InteractionState;
295 }
296 
297 //----------------------------------------------------------------------
StartWidgetDefinition(double e[2])298 void vtkBiDimensionalRepresentation2D::StartWidgetDefinition(double e[2])
299 {
300   double pos[3];
301   pos[0] = e[0];
302   pos[1] = e[1];
303   pos[2] = 0.0;
304 
305   this->SetPoint1DisplayPosition(pos);
306   this->SetPoint2DisplayPosition(pos);
307   this->SetPoint3DisplayPosition(pos);
308   this->SetPoint4DisplayPosition(pos);
309 
310   this->StartEventPosition[0] = pos[0];
311   this->StartEventPosition[1] = pos[1];
312   this->StartEventPosition[2] = pos[2];
313 }
314 
315 //----------------------------------------------------------------------
Point2WidgetInteraction(double e[2])316 void vtkBiDimensionalRepresentation2D::Point2WidgetInteraction(double e[2])
317 {
318   double pos[3],p1[3];
319   pos[0] = e[0];
320   pos[1] = e[1];
321   pos[2] = 0.0;
322 
323   // Make sure that the two points are not coincident
324   this->GetPoint1DisplayPosition(p1);
325   if ( ((pos[0]-p1[0])*(pos[0]-p1[0]) + (pos[1]-p1[1])*(pos[1]-p1[1])) < 2 )
326   {
327     pos[0] += 2;
328   }
329   this->SetPoint2DisplayPosition(pos);
330 }
331 
332 //----------------------------------------------------------------------
333 // This method is called when Point3 is to be manipulated. Note that Point3
334 // and Point4 are constrained relative to Line1. As a result, manipulating P3
335 // results in manipulating P4.
Point3WidgetInteraction(double e[2])336 void vtkBiDimensionalRepresentation2D::Point3WidgetInteraction(double e[2])
337 {
338   double p1[3], p2[3], p3[3], p4[3];
339   double slope1[3], slope2[3];
340 
341   // Start by getting the coordinates (P1,P2) defining Line1. Also get
342   // characteristics of Line1 including its slope, etc.
343   this->GetPoint1WorldPosition(p1);
344   this->GetPoint2WorldPosition(p2);
345   slope1[0] = p2[0] - p1[0];
346   slope1[1] = p2[1] - p1[1];
347   slope2[0] = -slope1[1];
348   slope2[1] =  slope1[0];
349   slope2[2] = 0.0;
350   vtkMath::Normalize(slope2);
351 
352   // The current position of P3 is constrained to lie along Line1. Also,
353   // P4 is placed on the opposite side of Line1.
354   double pw[4], t, closest[3];
355   if ( this->Renderer )
356   {
357     this->Renderer->SetDisplayPoint(e[0],e[1],0.0);
358     this->Renderer->DisplayToWorld();
359     this->Renderer->GetWorldPoint(pw);
360   }
361   double dist = sqrt(vtkLine::DistanceToLine(pw,p1,p2,t,closest));
362 
363   // Set the positions of P3 and P4.
364   p3[0] = closest[0] + dist*slope2[0];
365   p3[1] = closest[1] + dist*slope2[1];
366   p3[2] = pw[2];
367   this->SetPoint3WorldPosition(p3);
368 
369   p4[0] = closest[0] - dist*slope2[0];
370   p4[1] = closest[1] - dist*slope2[1];
371   p4[2] = pw[2];
372   this->SetPoint4WorldPosition(p4);
373 }
374 
375 //----------------------------------------------------------------------
StartWidgetManipulation(double e[2])376 void vtkBiDimensionalRepresentation2D::StartWidgetManipulation(double e[2])
377 {
378   this->StartEventPosition[0] = e[0];
379   this->StartEventPosition[1] = e[1];
380   this->StartEventPosition[2] = 0.0;
381 
382   if ( this->Renderer )
383   {
384     this->Renderer->SetDisplayPoint(e[0],e[1],0.0);
385     this->Renderer->DisplayToWorld();
386     this->Renderer->GetWorldPoint(this->StartEventPositionWorld);
387   }
388 
389   this->GetPoint1WorldPosition(this->P1World);
390   this->GetPoint2WorldPosition(this->P2World);
391   this->GetPoint3WorldPosition(this->P3World);
392   this->GetPoint4WorldPosition(this->P4World);
393 
394   int i;
395   for (i=0; i<3; i++)
396   {
397     this->P21World[i] = this->P2World[i] - this->P1World[i];
398     this->P43World[i] = this->P4World[i] - this->P3World[i];
399   }
400 
401   vtkLine::Intersection(this->P1World,this->P2World,
402                         this->P3World,this->P4World,
403                         this->T21,this->T43);
404 
405   // Compute the center point
406   for (i=0; i<3; i++)
407   {
408     this->CenterWorld[i] = ((this->P1World[i] + this->T21*this->P21World[i]) +
409                             (this->P3World[i] + this->T43*this->P43World[i]))/2.0;
410   }
411 }
412 
413 //----------------------------------------------------------------------
414 // This handles all the nasty special cases when the length of the arms of the
415 // bidimensional widget become zero. Basically the method prevents the arms
416 // from getting too short.
ProjectOrthogonalPoint(double x[4],double y[3],double x1[3],double x2[3],double x21[3],double dir,double xP[3])417 void vtkBiDimensionalRepresentation2D::ProjectOrthogonalPoint(double x[4], double y[3], double x1[3], double x2[3],
418                                                               double x21[3], double dir, double xP[3])
419 {
420   double t, closest[3], slope[3], dist;
421 
422   // determine the distance from the other (orthogonal) line
423   dist = dir * sqrt(vtkLine::DistanceToLine(x,x1,x2,t,closest));
424 
425   // get the closest point on the other line, use its "mate" point to define the projection point,
426   // this keeps everything orthogonal.
427   vtkLine::DistanceToLine(y,x1,x2,t,closest);
428 
429   // Project the point "dist" orthogonal to ray x21.
430   // Define an orthogonal line.
431   slope[0] = -x21[1];
432   slope[1] =  x21[0];
433   slope[2] = 0.0;
434 
435   // Project out the right distance along the calculated slope
436   vtkMath::Normalize(slope);
437   xP[0] = closest[0] + dist*slope[0];
438   xP[1] = closest[1] + dist*slope[1];
439   xP[2] = closest[2] + dist*slope[2];
440 
441   // Check to see what side the projection is on, clamp if necessary. Note that closest is modified so that the
442   // arms don't end up with zero length.
443   if ( ((xP[0]-closest[0])*(x[0]-closest[0]) + (xP[1]-closest[1])*(x[1]-closest[1]) + (xP[2]-closest[2])*(x[2]-closest[2])) < 0.0 )
444   {
445     // Convert closest point to display coordinates
446     double c1[3], c2[3], c21[3], cNew[3], xPNew[4];
447     this->Renderer->SetWorldPoint(closest[0],closest[1],closest[2],1.0);
448     this->Renderer->WorldToDisplay();
449     this->Renderer->GetDisplayPoint(c1);
450     // Convert vector in world space to display space
451     this->Renderer->SetWorldPoint(closest[0]+dir*slope[0],closest[1]+dir*slope[1],closest[2]+dir*slope[2],1.0);
452     this->Renderer->WorldToDisplay();
453     this->Renderer->GetDisplayPoint(c2);
454     c21[0] = c2[0] - c1[0];
455     c21[1] = c2[1] - c1[1];
456     c21[2] = c2[2] - c1[2];
457     vtkMath::Normalize(c21);
458 
459     // Perform vector addition in display space to get new point
460     cNew[0] = c1[0] + c21[0];
461     cNew[1] = c1[1] + c21[1];
462     cNew[2] = c1[2] + c21[2];
463 
464     this->Renderer->SetDisplayPoint(cNew[0],cNew[1],cNew[2]);
465     this->Renderer->DisplayToWorld();
466     this->Renderer->GetWorldPoint(xPNew);
467 
468     xP[0] = xPNew[0];
469     xP[1] = xPNew[1];
470     xP[2] = xPNew[2];
471   }
472 }
473 
474 //----------------------------------------------------------------------
475 // This method is tricky because it is constrained by Line1 and Line2.
476 // This method is invoked after all four points have been placed.
WidgetInteraction(double e[2])477 void vtkBiDimensionalRepresentation2D::WidgetInteraction(double e[2])
478 {
479   // Depending on the state, different motions are allowed.
480   if ( this->InteractionState == Outside || ! this->Renderer )
481   {
482     return;
483   }
484 
485   // Okay, go to work, convert this event to world coordinates
486   double pw[4], t, closest[3];
487   double p1[3], p2[3], p3[3], p4[3];
488   this->Renderer->SetDisplayPoint(e[0],e[1],0.0);
489   this->Renderer->DisplayToWorld();
490   this->Renderer->GetWorldPoint(pw);
491 
492   // depending on the state, perform different operations
493   if ( this->InteractionState == OnCenter )
494   {
495     for (int i=0; i<3; i++)
496     {
497       p1[i] = this->P1World[i] + (pw[i]-this->StartEventPositionWorld[i]);
498       p2[i] = this->P2World[i] + (pw[i]-this->StartEventPositionWorld[i]);
499       p3[i] = this->P3World[i] + (pw[i]-this->StartEventPositionWorld[i]);
500       p4[i] = this->P4World[i] + (pw[i]-this->StartEventPositionWorld[i]);
501     }
502     this->SetPoint1WorldPosition(p1);
503     this->SetPoint2WorldPosition(p2);
504     this->SetPoint3WorldPosition(p3);
505     this->SetPoint4WorldPosition(p4);
506   }
507   else if ( this->InteractionState == OnL1Outer ||
508             this->InteractionState == OnL2Outer) //rotate the representation
509   {
510     // compute rotation angle and center of rotation
511     double sc[3], ec[3], p1c[3], p2c[3], p3c[3], p4c[3];
512     for (int i=0; i<3; i++)
513     {
514       sc[i] = this->StartEventPositionWorld[i] - this->CenterWorld[i];
515       ec[i] = pw[i] - this->CenterWorld[i];
516       p1c[i] = this->P1World[i] - this->CenterWorld[i];
517       p2c[i] = this->P2World[i] - this->CenterWorld[i];
518       p3c[i] = this->P3World[i] - this->CenterWorld[i];
519       p4c[i] = this->P4World[i] - this->CenterWorld[i];
520     }
521     double theta = atan2(ec[1],ec[0]) - atan2(sc[1],sc[0]);
522     double r1 = vtkMath::Norm(p1c);
523     double r2 = vtkMath::Norm(p2c);
524     double r3 = vtkMath::Norm(p3c);
525     double r4 = vtkMath::Norm(p4c);
526     double theta1 = atan2(p1c[1],p1c[0]);
527     double theta2 = atan2(p2c[1],p2c[0]);
528     double theta3 = atan2(p3c[1],p3c[0]);
529     double theta4 = atan2(p4c[1],p4c[0]);
530 
531     //rotate the four points
532     p1[0] = this->CenterWorld[0] + r1*cos(theta+theta1);
533     p1[1] = this->CenterWorld[1] + r1*sin(theta+theta1);
534     p2[0] = this->CenterWorld[0] + r2*cos(theta+theta2);
535     p2[1] = this->CenterWorld[1] + r2*sin(theta+theta2);
536     p3[0] = this->CenterWorld[0] + r3*cos(theta+theta3);
537     p3[1] = this->CenterWorld[1] + r3*sin(theta+theta3);
538     p4[0] = this->CenterWorld[0] + r4*cos(theta+theta4);
539     p4[1] = this->CenterWorld[1] + r4*sin(theta+theta4);
540     p1[2] = this->P1World[2];
541     p2[2] = this->P2World[2];
542     p3[2] = this->P3World[2];
543     p4[2] = this->P4World[2];
544 
545     this->SetPoint1WorldPosition(p1);
546     this->SetPoint2WorldPosition(p2);
547     this->SetPoint3WorldPosition(p3);
548     this->SetPoint4WorldPosition(p4);
549   }
550   else if ( this->InteractionState == OnL1Inner )
551   {
552     vtkLine::DistanceToLine(pw,this->P3World,this->P4World,t,closest);
553     t = ( t < 0.0 ? 0.0 : (t > 1.0 ? 1.0 : t) );
554     for (int i=0; i<3; i++)
555     {
556       p1[i] = this->P1World[i] + (t-this->T43)*this->P43World[i];
557       p2[i] = this->P2World[i] + (t-this->T43)*this->P43World[i];
558     }
559 
560     // Set the positions of P1 and P2.
561     this->SetPoint1WorldPosition(p1);
562     this->SetPoint2WorldPosition(p2);
563   }
564   else if ( this->InteractionState == OnL2Inner )
565   {
566     vtkLine::DistanceToLine(pw,this->P1World,this->P2World,t,closest);
567     t = ( t < 0.0 ? 0.0 : (t > 1.0 ? 1.0 : t) );
568     for (int i=0; i<3; i++)
569     {
570       p3[i] = this->P3World[i] + (t-this->T21)*this->P21World[i];
571       p4[i] = this->P4World[i] + (t-this->T21)*this->P21World[i];
572     }
573 
574     // Set the positions of P3 and P4.
575     this->SetPoint3WorldPosition(p3);
576     this->SetPoint4WorldPosition(p4);
577   }
578   else if ( this->InteractionState == NearP1 )
579   {
580     this->ProjectOrthogonalPoint(pw,this->P2World,this->P3World,this->P4World,this->P43World,-1,p1);
581     this->SetPoint1WorldPosition(p1);
582   }
583   else if ( this->InteractionState == NearP2 )
584   {
585     this->ProjectOrthogonalPoint(pw,this->P1World,this->P3World,this->P4World,this->P43World,1,p2);
586     this->SetPoint2WorldPosition(p2);
587   }
588   else if ( this->InteractionState == NearP3 )
589   {
590     this->ProjectOrthogonalPoint(pw,this->P4World,this->P1World,this->P2World,this->P21World,1,p3);
591     this->SetPoint3WorldPosition(p3);
592   }
593   else if ( this->InteractionState == NearP4 )
594   {
595     this->ProjectOrthogonalPoint(pw,this->P3World,this->P1World,this->P2World,this->P21World,-1,p4);
596     this->SetPoint4WorldPosition(p4);
597   } //near P4
598 }
599 
600 //----------------------------------------------------------------------
BuildRepresentation()601 void vtkBiDimensionalRepresentation2D::BuildRepresentation()
602 {
603   if ( this->GetMTime() > this->BuildTime ||
604        this->Point1Representation->GetMTime() > this->BuildTime ||
605        this->Point2Representation->GetMTime() > this->BuildTime ||
606        this->Point3Representation->GetMTime() > this->BuildTime ||
607        this->Point4Representation->GetMTime() > this->BuildTime ||
608        (this->Renderer && this->Renderer->GetVTKWindow() &&
609         this->Renderer->GetVTKWindow()->GetMTime() > this->BuildTime) )
610   {
611     // Make sure that tolerance is consistent between handles and this representation
612     this->Point1Representation->SetTolerance(this->Tolerance);
613     this->Point2Representation->SetTolerance(this->Tolerance);
614     this->Point3Representation->SetTolerance(this->Tolerance);
615     this->Point4Representation->SetTolerance(this->Tolerance);
616 
617     // Now bring the lines up to date
618     if ( ! this->Line1Visibility )
619     {
620       return;
621     }
622 
623     char distStr1[256], distStr2[256];
624     double p1[3], p2[3], p3[3], p4[3];
625     this->GetPoint1DisplayPosition(p1);
626     this->GetPoint2DisplayPosition(p2);
627     this->GetPoint3DisplayPosition(p3);
628     this->GetPoint4DisplayPosition(p4);
629 
630     double wp1[3], wp2[3], wp3[3], wp4[3];
631     this->GetPoint1WorldPosition(wp1);
632     this->GetPoint2WorldPosition(wp2);
633     this->GetPoint3WorldPosition(wp3);
634     this->GetPoint4WorldPosition(wp4);
635 
636     this->LinePoints->SetPoint(0,p1);
637     this->LinePoints->SetPoint(1,p2);
638     this->LinePoints->SetPoint(2,p3);
639     this->LinePoints->SetPoint(3,p4);
640     this->LinePoints->Modified();
641 
642     this->LineCells->Reset();
643     this->LineCells->InsertNextCell(2);
644     this->LineCells->InsertCellPoint(0);
645     this->LineCells->InsertCellPoint(1);
646 
647     if ( this->Line2Visibility )
648     {
649       this->LineCells->InsertNextCell(2);
650       this->LineCells->InsertCellPoint(2);
651       this->LineCells->InsertCellPoint(3);
652     }
653 
654     double line1Dist = sqrt(vtkMath::Distance2BetweenPoints(wp1, wp2));
655     double line2Dist = 0;
656     if (this->Line2Visibility)
657     {
658       line2Dist = sqrt(vtkMath::Distance2BetweenPoints(wp3, wp4));
659     }
660     std::ostringstream label;
661     if (this->IDInitialized)
662     {
663       label << this->ID << ": ";
664     }
665     snprintf(distStr1,sizeof(distStr1),this->LabelFormat, line1Dist);
666     snprintf(distStr2,sizeof(distStr2),this->LabelFormat, line2Dist);
667 
668     if (line1Dist > line2Dist)
669     {
670       label << distStr1 << " x " << distStr2;
671     }
672     else
673     {
674       label << distStr2 << " x " << distStr1;
675     }
676     this->TextMapper->SetInput(label.str().c_str());
677 
678     // Adjust the font size
679     int stringSize[2], *winSize = this->Renderer->GetSize();
680     vtkTextMapper::SetRelativeFontSize(this->TextMapper, this->Renderer, winSize,
681                                        stringSize, 0.015);
682 
683     int maxX = VTK_INT_MIN, maxY = VTK_INT_MIN;
684     if (p1[1] > maxY)
685     {
686       maxX = static_cast<int>(p1[0]);
687       maxY = static_cast<int>(p1[1]);
688     }
689     if (p2[1] > maxY)
690     {
691       maxX = static_cast<int>(p2[0]);
692       maxY = static_cast<int>(p2[1]);
693     }
694     if (p3[1] > maxY)
695     {
696       maxX = static_cast<int>(p3[0]);
697       maxY = static_cast<int>(p3[1]);
698     }
699     if (p4[1] > maxY)
700     {
701       maxX = static_cast<int>(p4[0]);
702       maxY = static_cast<int>(p4[1]);
703     }
704     int minX = VTK_INT_MAX, minY = VTK_INT_MAX;
705     if (p1[1] < minY)
706     {
707       minX = static_cast<int>(p1[0]);
708       minY = static_cast<int>(p1[1]);
709     }
710     if (p2[1] < minY)
711     {
712       minX = static_cast<int>(p2[0]);
713       minY = static_cast<int>(p2[1]);
714     }
715     if (p3[1] < minY)
716     {
717       minX = static_cast<int>(p3[0]);
718       minY = static_cast<int>(p3[1]);
719     }
720     if (p4[1] < minY)
721     {
722       minX = static_cast<int>(p4[0]);
723       minY = static_cast<int>(p4[1]);
724     }
725     this->TextMapper->GetTextProperty()->SetJustificationToCentered();
726     if (this->ShowLabelAboveWidget)
727     {
728       this->TextActor->SetPosition(maxX, maxY + 9);
729       this->TextMapper->GetTextProperty()->SetVerticalJustificationToBottom();
730     }
731     else
732     {
733       this->TextActor->SetPosition(minX, minY - 9);
734       this->TextMapper->GetTextProperty()->SetVerticalJustificationToTop();
735     }
736 
737     this->BuildTime.Modified();
738   }
739 }
740 
741 //----------------------------------------------------------------------
GetLabelText()742 char* vtkBiDimensionalRepresentation2D::GetLabelText()
743 {
744   return this->TextMapper->GetInput();
745 }
746 
747 //----------------------------------------------------------------------
GetLabelPosition()748 double* vtkBiDimensionalRepresentation2D::GetLabelPosition()
749 {
750   return this->TextActor->GetPosition();
751 }
752 
753 //----------------------------------------------------------------------
GetLabelPosition(double pos[3])754 void vtkBiDimensionalRepresentation2D::GetLabelPosition(double pos[3])
755 {
756   this->TextActor->GetPositionCoordinate()->GetValue(pos);
757 }
758 
759 //----------------------------------------------------------------------
GetWorldLabelPosition(double pos[3])760 void vtkBiDimensionalRepresentation2D::GetWorldLabelPosition(double pos[3])
761 {
762   double viewportPos[3], worldPos[4];
763   pos[0] = pos[1] = pos[2] = 0.0;
764   if (!this->Renderer)
765   {
766     vtkErrorMacro("GetWorldLabelPosition: no renderer!");
767     return;
768   }
769   this->TextActor->GetPositionCoordinate()->GetValue(viewportPos);
770   this->Renderer->ViewportToNormalizedViewport(viewportPos[0], viewportPos[1]);
771   this->Renderer->NormalizedViewportToView(viewportPos[0], viewportPos[1], viewportPos[2]);
772   this->Renderer->SetViewPoint(viewportPos);
773   this->Renderer->ViewToWorld();
774   this->Renderer->GetWorldPoint(worldPos);
775 
776   if (worldPos[3] != 0.0)
777   {
778     pos[0] = worldPos[0]/worldPos[3];
779     pos[1] = worldPos[1]/worldPos[3];
780     pos[2] = worldPos[2]/worldPos[3];
781   }
782   else
783   {
784     vtkErrorMacro("GetWorldLabelPosition: world position at index 3 is 0, not dividing by 0");
785   }
786 }
787 
788 //----------------------------------------------------------------------
ReleaseGraphicsResources(vtkWindow * w)789 void vtkBiDimensionalRepresentation2D::ReleaseGraphicsResources(vtkWindow *w)
790 {
791   this->LineActor->ReleaseGraphicsResources(w);
792   this->TextActor->ReleaseGraphicsResources(w);
793 }
794 
795 
796 //----------------------------------------------------------------------
RenderOverlay(vtkViewport * viewport)797 int vtkBiDimensionalRepresentation2D::RenderOverlay(vtkViewport *viewport)
798 {
799   this->BuildRepresentation();
800 
801   int count = this->LineActor->RenderOverlay(viewport);
802   if ( this->Line1Visibility )
803   {
804     count += this->TextActor->RenderOverlay(viewport);
805   }
806   return count;
807 }
808 
809 
810 //----------------------------------------------------------------------
Highlight(int highlightOn)811 void vtkBiDimensionalRepresentation2D::Highlight(int highlightOn)
812 {
813   if ( highlightOn )
814   {
815     this->LineActor->SetProperty(this->SelectedLineProperty);
816   }
817   else
818   {
819     this->LineActor->SetProperty(this->LineProperty);
820   }
821 }
822 
823 //----------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)824 void vtkBiDimensionalRepresentation2D::PrintSelf(ostream& os, vtkIndent indent)
825 {
826   //Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h
827   this->Superclass::PrintSelf(os,indent);
828 
829   if ( this->TextProperty )
830   {
831     os << indent << "Text Property:\n";
832     this->TextProperty->PrintSelf(os,indent.GetNextIndent());
833   }
834   else
835   {
836     os << indent << "Property: (none)\n";
837   }
838 
839   if ( this->LineProperty )
840   {
841     os << indent << "Line Property:\n";
842     this->LineProperty->PrintSelf(os,indent.GetNextIndent());
843   }
844   else
845   {
846     os << indent << "Line Property: (none)\n";
847   }
848 
849   if ( this->SelectedLineProperty )
850   {
851     os << indent << "Selected Line Property:\n";
852     this->SelectedLineProperty->PrintSelf(os,indent.GetNextIndent());
853   }
854   else
855   {
856     os << indent << "Selected Line Property: (none)\n";
857   }
858 }
859 
860