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