1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    vtkControlPointsItem.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 "vtkAxis.h"
17 #include "vtkBrush.h"
18 #include "vtkCallbackCommand.h"
19 #include "vtkContext2D.h"
20 #include "vtkContextDevice2D.h"
21 #include "vtkContextKeyEvent.h"
22 #include "vtkContextMouseEvent.h"
23 #include "vtkContextScene.h"
24 #include "vtkControlPointsItem.h"
25 #include "vtkIdTypeArray.h"
26 #include "vtkNew.h"
27 #include "vtkObjectFactory.h"
28 #include "vtkPen.h"
29 #include "vtkPoints2D.h"
30 #include "vtkRenderWindowInteractor.h"
31 #include "vtkSmartPointer.h"
32 #include "vtkTransform2D.h"
33 #include "vtkVectorOperators.h"
34 
35 #include <algorithm>
36 #include <cassert>
37 #include <limits>
38 
39 //-----------------------------------------------------------------------------
vtkControlPointsItem()40 vtkControlPointsItem::vtkControlPointsItem()
41 {
42   this->Pen->SetLineType(vtkPen::SOLID_LINE);
43   this->Pen->SetWidth(2.);
44   this->Pen->SetColor(140, 144, 125, 200);
45   this->Brush->SetColor(125, 135, 144, 200);
46 
47   this->SelectedPointPen = vtkPen::New();
48   this->SelectedPointPen->SetWidth(2.);
49   // 98, 140, 178
50   this->SelectedPointPen->SetColor(63, 90, 115, 200);
51   //this->SelectedPointPen->SetColor(98, 140, 178, 200);
52   this->SelectedPointBrush = vtkBrush::New();
53   this->SelectedPointBrush->SetColor(58, 121, 178, 200);
54 
55   this->Selection = vtkIdTypeArray::New();
56   this->CurrentPoint = -1;
57 
58   this->BlockUpdates = 0;
59   this->StartedInteractions = 0;
60   this->StartedChanges = 0;
61 
62   this->Callback = vtkCallbackCommand::New();
63   this->Callback->SetClientData(this);
64   this->Callback->SetCallback(
65     vtkControlPointsItem::CallComputePoints);
66 
67   this->Bounds[0] = this->Bounds[2] = 0.;
68   this->Bounds[1] = this->Bounds[3] = -1.;
69   this->UserBounds[0] = this->UserBounds[2] = 0.;
70   this->UserBounds[1] = this->UserBounds[3] = -1.;
71   this->ValidBounds[0] = this->ValidBounds[2] = 0.;
72   this->ValidBounds[1] = this->ValidBounds[3] = -1.;
73 
74   this->ScreenPointRadius = 6.f;
75   this->Transform = vtkTransform2D::New();
76 
77   this->StrokeMode = false;
78   this->SwitchPointsMode = false;
79   this->MouseMoved = false;
80   this->EnforceValidFunction = true;
81   this->PointToDelete = -1;
82   this->PointAboutToBeDeleted = false;
83   this->PointToToggle = -1;
84   this->PointAboutToBeToggled = false;
85   this->InvertShadow = false;
86   this->EndPointsXMovable = true;
87   this->EndPointsYMovable = true;
88   this->EndPointsRemovable = true;
89   this->ShowLabels = false;
90   this->LabelFormat = NULL;
91   this->SetLabelFormat("%.3f, %.3f");
92 }
93 
94 //-----------------------------------------------------------------------------
~vtkControlPointsItem()95 vtkControlPointsItem::~vtkControlPointsItem()
96 {
97   this->SetLabelFormat(NULL);
98   if (this->Callback)
99     {
100     this->Callback->Delete();
101     this->Callback = 0;
102     }
103   if (this->SelectedPointPen)
104     {
105     this->SelectedPointPen->Delete();
106     this->SelectedPointPen = 0;
107     }
108   if (this->SelectedPointBrush)
109     {
110     this->SelectedPointBrush->Delete();
111     this->SelectedPointBrush = 0;
112     }
113   if (this->Transform)
114     {
115     this->Transform->Delete();
116     this->Transform = 0;
117     }
118 }
119 
120 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)121 void vtkControlPointsItem::PrintSelf(ostream &os, vtkIndent indent)
122 {
123   this->Superclass::PrintSelf(os, indent);
124 
125   os << indent << "EndPointsXMovable: " << this->EndPointsXMovable << endl;
126   os << indent << "EndPointsYMovable: " << this->EndPointsYMovable << endl;
127   os << indent << "EndPointsRemovable: " << this->EndPointsRemovable << endl;
128   os << indent << "ShowLabels: " << this->ShowLabels << endl;
129 }
130 
131 //-----------------------------------------------------------------------------
GetBounds(double bounds[4])132 void vtkControlPointsItem::GetBounds(double bounds[4])
133 {
134   // valid user bounds ? use them
135   if (this->UserBounds[0] <= this->UserBounds[1] &&
136       this->UserBounds[2] <= this->UserBounds[3])
137     {
138     bounds[0] = this->UserBounds[0];
139     bounds[1] = this->UserBounds[1];
140     bounds[2] = this->UserBounds[2];
141     bounds[3] = this->UserBounds[3];
142     return;
143     }
144   // invalid bounds ? compute them
145   if (!(this->Bounds[0] <= this->Bounds[1] &&
146         this->Bounds[2] > this->Bounds[3]))
147     {
148     this->ComputeBounds();
149     }
150   bounds[0] = this->Bounds[0];
151   bounds[1] = this->Bounds[1];
152   bounds[2] = this->Bounds[2];
153   bounds[3] = this->Bounds[3];
154 }
155 
156 //-----------------------------------------------------------------------------
ResetBounds()157 void vtkControlPointsItem::ResetBounds()
158 {
159   this->Bounds[0] = 0.;
160   this->Bounds[1] = -1.;
161   this->Bounds[2] = 0.;
162   this->Bounds[3] = -1.;
163 }
164 
165 //-----------------------------------------------------------------------------
ComputeBounds()166 void vtkControlPointsItem::ComputeBounds()
167 {
168   double oldBounds[4];
169   oldBounds[0] = this->Bounds[0];
170   oldBounds[1] = this->Bounds[1];
171   oldBounds[2] = this->Bounds[2];
172   oldBounds[3] = this->Bounds[3];
173 
174   this->ComputeBounds(this->Bounds);
175 
176   if (this->Bounds[0] != oldBounds[0] ||
177       this->Bounds[1] != oldBounds[1] ||
178       this->Bounds[2] != oldBounds[2] ||
179       this->Bounds[3] != oldBounds[3])
180     {
181     this->Modified();
182     }
183 }
184 
185 //-----------------------------------------------------------------------------
ComputeBounds(double * bounds)186 void vtkControlPointsItem::ComputeBounds( double* bounds)
187 {
188   bounds[0] = bounds[2] =  VTK_DOUBLE_MAX;
189   bounds[1] = bounds[3] = -VTK_DOUBLE_MAX;
190   for (vtkIdType i=0; i < this->GetNumberOfPoints(); ++i)
191     {
192     double point[4];
193     this->GetControlPoint(i, point);
194     bounds[0] = std::min(bounds[0], point[0]);
195     bounds[1] = std::max(bounds[1], point[0]);
196     bounds[2] = std::min(bounds[2], point[1]);
197     bounds[3] = std::max(bounds[3], point[1]);
198     }
199 }
200 
201 //-----------------------------------------------------------------------------
Paint(vtkContext2D * painter)202 bool vtkControlPointsItem::Paint(vtkContext2D* painter)
203 {
204   painter->GetDevice()->EnableClipping(false);
205   painter->ApplyPen(this->Pen);
206   painter->ApplyBrush(this->Brush);
207   this->InvertShadow = false;
208   this->DrawUnselectedPoints(painter);
209 
210   painter->GetPen()->SetLineType(vtkPen::SOLID_LINE);
211   //painter->GetPen()->SetColorF(0.87, 0.87, 1.);
212   //painter->GetBrush()->SetColorF(0.75, 0.75, 0.95, 0.65);
213   //float oldPenWidth = painter->GetPen()->GetWidth();
214   painter->ApplyPen(this->SelectedPointPen);
215   painter->ApplyBrush(this->SelectedPointBrush);
216   this->InvertShadow = true;
217   float oldScreenPointRadius = this->ScreenPointRadius;
218   if (this->Selection && this->Selection->GetNumberOfTuples())
219     {
220     //painter->GetPen()->SetWidth(oldPenWidth * 1.4);
221     //this->ScreenPointRadius = oldScreenPointRadius * 1.1;
222     this->DrawSelectedPoints(painter);
223     }
224   this->ScreenPointRadius = oldScreenPointRadius;
225   this->Transform->SetMatrix(painter->GetTransform()->GetMatrix());
226 
227   painter->GetDevice()->EnableClipping(true);
228   this->PaintChildren(painter);
229   return true;
230 }
231 
232 //-----------------------------------------------------------------------------
StartChanges()233 void vtkControlPointsItem::StartChanges()
234 {
235   ++this->StartedChanges;
236   if (this->StartedChanges == 1)
237     {
238     this->InvokeEvent(vtkCommand::StartEvent);
239     this->emitEvent(vtkCommand::StartEvent);
240     }
241 }
242 
243 //-----------------------------------------------------------------------------
EndChanges()244 void vtkControlPointsItem::EndChanges()
245 {
246   --this->StartedChanges;
247   assert(this->StartedChanges >=0);
248   if (this->StartedChanges == 0)
249     {
250     this->emitEvent(vtkCommand::EndEvent);
251     this->InvokeEvent(vtkCommand::EndEvent);
252     }
253 }
254 
255 //-----------------------------------------------------------------------------
StartInteraction()256 void vtkControlPointsItem::StartInteraction()
257 {
258   ++this->StartedInteractions;
259   this->emitEvent(vtkCommand::StartInteractionEvent);
260 }
261 
262 //-----------------------------------------------------------------------------
StartInteractionIfNotStarted()263 void vtkControlPointsItem::StartInteractionIfNotStarted()
264 {
265   if (this->GetInteractionsCount() == 0)
266     {
267     this->StartInteraction();
268     }
269 }
270 
271 //-----------------------------------------------------------------------------
Interaction()272 void vtkControlPointsItem::Interaction()
273 {
274   assert(this->StartedInteractions > 0);
275   this->emitEvent(vtkCommand::InteractionEvent);
276 }
277 
278 //-----------------------------------------------------------------------------
EndInteraction()279 void vtkControlPointsItem::EndInteraction()
280 {
281   --this->StartedInteractions;
282   assert(this->StartedInteractions >= 0);
283   this->emitEvent(vtkCommand::EndInteractionEvent);
284 }
285 
286 //-----------------------------------------------------------------------------
GetInteractionsCount() const287 int vtkControlPointsItem::GetInteractionsCount()const
288 {
289   return this->StartedInteractions;
290 }
291 
292 //-----------------------------------------------------------------------------
293 //void vtkControlPointsItem::emitEvent(unsigned long event, void* params);
294 
295 //-----------------------------------------------------------------------------
CallComputePoints(vtkObject * vtkNotUsed (sender),unsigned long event,void * receiver,void * vtkNotUsed (params))296 void vtkControlPointsItem::CallComputePoints(
297   vtkObject* vtkNotUsed(sender), unsigned long event,
298   void* receiver, void* vtkNotUsed(params))
299 {
300   vtkControlPointsItem* item =
301     reinterpret_cast<vtkControlPointsItem*>(receiver);
302   switch(event)
303     {
304     case vtkCommand::StartEvent:
305       ++item->BlockUpdates;
306       break;
307     case vtkCommand::EndEvent:
308       --item->BlockUpdates;
309       if (item->BlockUpdates == 0)
310         {
311         item->ComputePoints();
312         }
313       break;
314     case vtkCommand::ModifiedEvent:
315       item->ComputePoints();
316       break;
317     default:
318       break;
319     }
320 }
321 
322 //-----------------------------------------------------------------------------
ComputePoints()323 void vtkControlPointsItem::ComputePoints()
324 {
325   if (this->BlockUpdates > 0)
326     {
327     return;
328     }
329 
330   if (this->Selection && this->GetNumberOfPoints() == 0)
331     {
332     this->Selection->SetNumberOfTuples(0);
333     }
334 
335   const int selectedPointCount = this->Selection ?
336         this->Selection->GetNumberOfTuples() : 0;
337   if (selectedPointCount)
338     {
339     vtkIdTypeArray* oldSelection = this->Selection;
340     this->Selection = vtkIdTypeArray::New();
341     for (vtkIdType i = 0; i < selectedPointCount; ++i)
342       {
343       if (oldSelection->GetValue(i) < this->GetNumberOfPoints())
344         {
345         this->SelectPoint(oldSelection->GetValue(i));
346         }
347       }
348     oldSelection->Delete();
349     }
350 
351   if (this->GetScene())
352     {
353     this->GetScene()->SetDirty(true);
354     }
355   this->Modified();
356 }
357 
358 //-----------------------------------------------------------------------------
TransformScreenToData(const vtkVector2f & in,vtkVector2f & out)359 void vtkControlPointsItem::TransformScreenToData(const vtkVector2f& in, vtkVector2f& out)
360 {
361   out = in;
362 
363   // inverse shift/scale from screen space.
364   const vtkRectd& ss = this->ShiftScale;
365   out.SetX(static_cast<float>((out.GetX() / ss[2]) - ss[0]));
366   out.SetY(static_cast<float>((out.GetY() / ss[3]) - ss[1]));
367 
368   if (this->UsingLogScale())
369     {
370     // using log scale.
371     double bounds[4];
372     this->ComputeBounds(bounds);
373 
374     double posX = in.GetX();
375     double normVal = (posX - bounds[0])/(bounds[1] - bounds[0]);
376     double lval = log10(bounds[0]) + normVal*(log10(bounds[1]) - log10(bounds[0]));
377     posX = pow(10.0, lval);
378     out.SetX(posX);
379     }
380 }
381 
382 //-----------------------------------------------------------------------------
TransformDataToScreen(const vtkVector2f & in,vtkVector2f & out)383 void vtkControlPointsItem::TransformDataToScreen(const vtkVector2f& in, vtkVector2f& out)
384 {
385   out = in;
386   if (this->UsingLogScale())
387     {
388     double bounds[4];
389     this->ComputeBounds(bounds);
390 
391     double posX = in.GetX();
392     double lnormVal = (log10(posX) - log10(bounds[0])) /
393                       (log10(bounds[1]) - log10(bounds[0]));
394     posX = bounds[0] + lnormVal * (bounds[1] - bounds[0]);
395     out.SetX(posX);
396     }
397 
398   // now, shift/scale to screen space.
399   const vtkRectd& ss = this->ShiftScale;
400   out.SetX(static_cast<float>((out.GetX() + ss[0]) * ss[2]));
401   out.SetY(static_cast<float>((out.GetY() + ss[1]) * ss[3]));
402 }
403 
404 //-----------------------------------------------------------------------------
Hit(const vtkContextMouseEvent & mouse)405 bool vtkControlPointsItem::Hit(const vtkContextMouseEvent &mouse)
406 {
407   vtkVector2f vpos = mouse.GetPos();
408   this->TransformScreenToData(vpos, vpos);
409   double pos[2];
410   pos[0] = vpos.GetX();
411   pos[1] = vpos.GetY();
412   double bounds[4];
413   this->GetBounds(bounds);
414   bool clamped = this->ClampPos(pos, bounds);
415   if (!clamped)
416     {
417     return true;
418     }
419   // maybe the cursor is over the first or last point (which could be outside
420   // the bounds because of the screen point size).
421   pos[0] = vpos.GetX();
422   pos[1] = vpos.GetY();
423   for (int i = 0; i < this->GetNumberOfPoints(); ++i)
424     {
425     if (this->IsOverPoint(pos, i))
426       {
427       return true;
428       }
429     }
430   return false;
431 }
432 
433 //-----------------------------------------------------------------------------
ClampPos(double pos[2],double bounds[4])434 bool vtkControlPointsItem::ClampPos(double pos[2], double bounds[4])
435 {
436   if (bounds[1] < bounds[0] || bounds[3] < bounds[2])
437     {
438     // bounds are not valid. Don't clamp.
439     return false;
440     }
441   bool clamped = false;
442   if (pos[0] < bounds[0])
443     {
444     pos[0] = bounds[0];
445     clamped = true;
446     }
447   if (pos[0] > bounds[1])
448     {
449     pos[0] = bounds[1];
450     clamped = true;
451     }
452   if (pos[1] < 0.)
453     {
454     pos[1] = 0.;
455     clamped = true;
456     }
457   if (pos[1] > 1.)
458     {
459     pos[1] = 1.;
460     clamped = true;
461     }
462   return clamped;
463 }
464 
465 //-----------------------------------------------------------------------------
ClampValidPos(double pos[2])466 bool vtkControlPointsItem::ClampValidPos(double pos[2])
467 {
468   double validBounds[4];
469   this->GetValidBounds(validBounds);
470   if (validBounds[0] > this->ValidBounds[1] ||
471       validBounds[2] > this->ValidBounds[3])
472     {
473     double bounds[4];
474     this->GetBounds(bounds);
475     return this->ClampPos(pos, bounds);
476     }
477   return this->ClampPos(pos, validBounds);
478 }
479 
480 //-----------------------------------------------------------------------------
DrawUnselectedPoints(vtkContext2D * painter)481 void vtkControlPointsItem::DrawUnselectedPoints(vtkContext2D* painter)
482 {
483   const int count = this->GetNumberOfPoints();
484   for (vtkIdType i = 0; i < count; ++i)
485     {
486     vtkIdType idx = this->Selection ? this->Selection->LookupValue(i) : -1;
487     if (idx != -1)
488       {
489       continue;
490       }
491     this->DrawPoint(painter, i);
492     }
493 }
494 
495 //-----------------------------------------------------------------------------
DrawSelectedPoints(vtkContext2D * painter)496 void vtkControlPointsItem::DrawSelectedPoints(vtkContext2D* painter)
497 {
498   const int count = this->Selection ? this->Selection->GetNumberOfTuples() : 0;
499   for (vtkIdType i = 0; i < count; ++i)
500     {
501     vtkIdType index = this->Selection->GetValue(i);
502     assert(index != -1);
503     this->DrawPoint(painter, index);
504     }
505 }
506 
507 //-----------------------------------------------------------------------------
DrawPoint(vtkContext2D * painter,vtkIdType index)508 void vtkControlPointsItem::DrawPoint(vtkContext2D* painter, vtkIdType index)
509 {
510   assert(index != -1);
511   double point[4];
512   this->GetControlPoint(index, point);
513 
514   vtkVector2f vpoint(point[0], point[1]);
515   this->TransformDataToScreen(vpoint, vpoint);
516   point[0] = vpoint.GetX();
517   point[1] = vpoint.GetY();
518 
519   double pointInScene[2];
520   vtkTransform2D* sceneTransform = painter->GetTransform();
521   sceneTransform->TransformPoints(point, pointInScene, 1);
522 
523   vtkSmartPointer<vtkTransform2D> translation =
524     vtkSmartPointer<vtkTransform2D>::New();
525   translation->Translate(pointInScene[0], pointInScene[1]);
526 
527   painter->PushMatrix();
528   painter->SetTransform(translation);
529 
530   unsigned char brushOpacity = painter->GetBrush()->GetOpacity();
531   unsigned char penColor[3];
532   painter->GetPen()->GetColor(penColor);
533   unsigned char penOpacity = painter->GetPen()->GetOpacity();
534   //float width = painter->GetPen()->GetWidth();
535 
536   float radius = this->ScreenPointRadius;
537   bool invertShadow = this->InvertShadow;
538   unsigned char color[3] = {penColor[0], penColor[1], penColor[2]};
539 
540   if (this->PointToToggle == index && this->PointAboutToBeToggled)
541     {
542     invertShadow = !invertShadow;
543     }
544   if (this->PointToDelete == index && this->PointAboutToBeDeleted)
545     {
546     invertShadow = !invertShadow;
547     color[0] = 255;
548     color[1] = 0;
549     color[2] = 0;
550     }
551   if (this->CurrentPoint == index)
552     {
553     radius = this->ScreenPointRadius * 1.3;
554     color[0] = 255;
555     color[1] = 0;
556     color[2] = 255;
557     }
558 
559   painter->GetPen()->SetColor(color);
560   painter->DrawArc(0.f, 0.f, radius, 0.f, 360.f);
561 
562   painter->GetBrush()->SetOpacity(0);
563   //painter->GetPen()->SetWidth(2.0f);
564 
565   unsigned char lightPenColor[4];
566   lightPenColor[0] = std::min(color[0] + 100, 255);
567   lightPenColor[1] = std::min(color[1] + 100, 255);
568   lightPenColor[2] = std::min(color[2] + 100, 255);
569   lightPenColor[3] = penOpacity;
570 
571   unsigned char darkPenColor[4];
572   darkPenColor[0] = std::max(color[0] - 50, 0);
573   darkPenColor[1] = std::max(color[1] - 50, 0);
574   darkPenColor[2] = std::max(color[2] - 50, 0);
575   darkPenColor[3] = penOpacity;
576 
577   painter->GetPen()->SetColor(invertShadow ? lightPenColor : darkPenColor);
578   painter->DrawArc(0.f, 0.f, radius - 1.0, 200.f, 380.f);
579   painter->GetPen()->SetColor(invertShadow ? darkPenColor : lightPenColor);
580   painter->DrawArc(0.f, 0.f, radius - 1.0, 20.f, 200.f);
581 
582   painter->GetPen()->SetColor(color);
583   if (this->PointToDelete == index && this->PointAboutToBeDeleted)
584     {
585     painter->DrawLine(-radius, -radius, radius, radius);
586     painter->DrawLine(-radius, radius, radius, -radius);
587     }
588 
589   painter->GetPen()->SetColor(penColor);
590 
591   if (this->ShowLabels && (/*index == 0 ||
592                            index == this->GetNumberOfPoints()-1 || */
593                            this->GetCurrentPoint() == index))
594     {
595     translation->Translate(0, radius+5);
596     painter->SetTransform(translation);
597     vtkStdString label = this->GetControlPointLabel(index);
598 
599     vtkVector2f bounds[2];
600     painter->ComputeStringBounds(label, bounds[0].GetData());
601     if (bounds[1].GetX() != 0.0f && bounds[1].GetY() != 0.0f)
602       {
603       float scale[2];
604       float position[2];
605       painter->GetTransform()->GetScale(scale);
606       painter->GetTransform()->GetPosition(position);
607 
608       double brushColor[4];
609       painter->GetBrush()->GetColorF(brushColor);
610       painter->GetBrush()->SetColorF(1, 1, 1, 1);
611       painter->GetBrush()->SetOpacityF(0.75);
612       painter->GetPen()->SetOpacity(0);
613       bounds[0] = vtkVector2f(-5/scale[0], -3/scale[1]);
614       bounds[1] = vtkVector2f(bounds[1].GetX()+10/scale[0],
615         bounds[1].GetY()+10/scale[1]);
616 
617       // Pull the tooltip back in if it will go off the edge of the screen.
618       float maxX = (this->Scene->GetViewWidth() - position[0])/scale[0];
619       if (bounds[0].GetX() >= maxX - bounds[1].GetX())
620         {
621         bounds[0].SetX(maxX - bounds[1].GetX());
622         }
623       // Pull the tooltip down in if it will go off the edge of the screen.
624       float maxY = (this->Scene->GetViewHeight() - position[1])/scale[1];
625       if (bounds[0].GetY() >= maxY - bounds[1].GetY())
626         {
627         bounds[0].SetY(maxY - bounds[1].GetY());
628         }
629       painter->DrawRect(bounds[0].GetX(), bounds[0].GetY(), bounds[1].GetX(), bounds[1].GetY());
630       painter->DrawString(bounds[0].GetX()+5/scale[0], bounds[0].GetY()+3/scale[1], label);
631       painter->GetBrush()->SetColorF(brushColor);
632       }
633     }
634 
635   painter->GetPen()->SetOpacity(penOpacity);
636   //painter->GetPen()->SetWidth(width);
637   painter->GetBrush()->SetOpacity(brushOpacity);
638 
639   painter->PopMatrix();
640 }
641 
642 //-----------------------------------------------------------------------------
SelectPoint(double * currentPoint)643 void vtkControlPointsItem::SelectPoint(double* currentPoint)
644 {
645   vtkIdType pointId = this->FindPoint(currentPoint);
646   if (pointId == -1)
647     {
648     vtkErrorMacro( << "try to select a point that doesn't exist");
649     return;
650     }
651   this->SelectPoint(pointId);
652 }
653 
654 //-----------------------------------------------------------------------------
SelectPoint(vtkIdType pointId)655 void vtkControlPointsItem::SelectPoint(vtkIdType pointId)
656 {
657   if (!this->Selection || this->Selection->LookupValue(pointId) != -1)
658     {
659     return;
660     }
661   this->Selection->InsertNextValue(pointId);
662   this->GetScene()->SetDirty(true);
663 }
664 
665 //-----------------------------------------------------------------------------
SelectAllPoints()666 void vtkControlPointsItem::SelectAllPoints()
667 {
668   this->DeselectAllPoints();
669   const int count = this->GetNumberOfPoints();
670   for (vtkIdType i = 0; i < count; ++i)
671     {
672     this->SelectPoint(i);
673     }
674 }
675 
676 //-----------------------------------------------------------------------------
DeselectPoint(double * point)677 void vtkControlPointsItem::DeselectPoint(double* point)
678 {
679   // make sure the point belongs to the list of points
680   vtkIdType pointId = this->FindPoint(point);
681   if (pointId == -1)
682     {
683     vtkErrorMacro( << "try to deselect a point that doesn't exist");
684     return;
685     }
686   this->DeselectPoint(pointId);
687 }
688 
689 //-----------------------------------------------------------------------------
DeselectPoint(vtkIdType pointId)690 void vtkControlPointsItem::DeselectPoint(vtkIdType pointId)
691 {
692   vtkIdType selectionPointId = this->Selection
693       ? this->Selection->LookupValue(pointId) : -1;
694   if (selectionPointId == -1)
695     {
696     //vtkErrorMacro(<< "Point:" << pointId << " was not selected");
697     return;
698     }
699   this->Selection->RemoveTuple(selectionPointId);
700   this->GetScene()->SetDirty(true);
701 }
702 
703 //-----------------------------------------------------------------------------
DeselectAllPoints()704 void vtkControlPointsItem::DeselectAllPoints()
705 {
706   if (this->GetNumberOfSelectedPoints() == 0)
707     {
708     return;
709     }
710   this->Selection->SetNumberOfTuples(0);
711   this->GetScene()->SetDirty(true);
712 }
713 
714 //-----------------------------------------------------------------------------
ToggleSelectPoint(double * currentPoint)715 void vtkControlPointsItem::ToggleSelectPoint(double* currentPoint)
716 {
717   // make sure the point belongs to the list of points
718   vtkIdType pointId = this->FindPoint(currentPoint);
719   if (pointId == -1)
720     {
721     vtkErrorMacro( << "try to toggle a point that doesn't exist");
722     return;
723     }
724   this->ToggleSelectPoint(pointId);
725 }
726 
727 //-----------------------------------------------------------------------------
ToggleSelectPoint(vtkIdType pointId)728 void vtkControlPointsItem::ToggleSelectPoint(vtkIdType pointId)
729 {
730   vtkIdType selectionId = this->Selection
731       ? this->Selection->LookupValue(pointId) : -1;
732   if (selectionId != -1)
733     {
734     this->DeselectPoint(pointId);
735     return;
736     }
737   this->SelectPoint(pointId);
738 }
739 
740 //-----------------------------------------------------------------------------
SelectPoints(const vtkVector2f & min,const vtkVector2f & max)741 bool vtkControlPointsItem::SelectPoints(const vtkVector2f& min, const vtkVector2f& max)
742 {
743   bool atLeast1PointSelected = false;
744   const int numberOfPoints = this->GetNumberOfPoints();
745   for(vtkIdType i = 0; i < numberOfPoints; ++i)
746     {
747     double point[4];
748     this->GetControlPoint(i, point);
749     if (point[0] >= min.GetX() && point[0] <= max.GetX() &&
750         point[1] >= min.GetY() && point[1] <= max.GetY())
751       {
752       this->SelectPoint(i);
753       atLeast1PointSelected = true;
754       }
755     else
756       {
757       this->DeselectPoint(i);
758       }
759     }
760   return atLeast1PointSelected;
761 }
762 
763 //-----------------------------------------------------------------------------
GetNumberOfSelectedPoints() const764 vtkIdType vtkControlPointsItem::GetNumberOfSelectedPoints()const
765 {
766   return this->Selection ? this->Selection->GetNumberOfTuples() : 0;
767 }
768 
769 //-----------------------------------------------------------------------------
GetCurrentPoint() const770 vtkIdType vtkControlPointsItem::GetCurrentPoint()const
771 {
772   return this->CurrentPoint;
773 }
774 /*
775 //-----------------------------------------------------------------------------
776 vtkIdType vtkControlPointsItem::FindPoint(double* pos, double tolerance)
777 {
778   if (tolerance < std::numeric_limits<float>::epsilon())
779     {
780     tolerance = std::numeric_limits<float>::epsilon();
781     }
782   // make sure the point belongs to the list of points
783   vtkIdType pointId = -1;
784   double minDist = VTK_DOUBLE_MAX;
785   const int numberOfPoints = this->GetNumberOfPoints();
786   for(vtkIdType i = 0; i < numberOfPoints; ++i)
787     {
788     double point[4];
789     this->GetControlPoint(i, point);
790     double distance = (point[0] - pos[0]) * (point[0] - pos[0]) +
791       (point[1] - pos[1]) * (point[1] - pos[1]);
792     if (distance <= tolerance)
793       {
794       if (distance == 0.)
795         {// we found the best match ever
796         return i;
797         }
798       else if (distance < minDist)
799         {// we found something not too bad, we maybe we can find closer
800         pointId = i;
801         minDist = distance;
802         }
803       }
804     // don't search any further if the x is already too large
805     //if (point[0] > pos[0] + this->ItemPointRadius2)
806     //  {
807     //  break;
808     //  }
809     }
810   return pointId;
811 }
812 */
813 
814 //-----------------------------------------------------------------------------
IsOverPoint(double * pos,vtkIdType pointId)815 bool vtkControlPointsItem::IsOverPoint(double* pos, vtkIdType pointId)
816 {
817   if (pointId < 0 || pointId >= this->GetNumberOfPoints())
818     {
819     return false;
820     }
821 
822   double screenPos[2];
823   this->Transform->TransformPoints(pos, screenPos, 1);
824 
825   double point[4];
826   this->GetControlPoint(pointId, point);
827   double screenPoint[2];
828   this->Transform->TransformPoints(point, screenPoint, 1);
829 
830   double distance2 =
831     (screenPoint[0] - screenPos[0]) * (screenPoint[0] - screenPos[0]) +
832     (screenPoint[1] - screenPos[1]) * (screenPoint[1] - screenPos[1]);
833   double tolerance = 1.3;
834   double radius2 = this->ScreenPointRadius * this->ScreenPointRadius
835     * tolerance * tolerance;
836   return distance2 <= radius2;
837 }
838 
839 //-----------------------------------------------------------------------------
FindPoint(double * _pos)840 vtkIdType vtkControlPointsItem::FindPoint(double* _pos)
841 {
842   vtkVector2f vpos(_pos[0], _pos[1]);
843   this->TransformDataToScreen(vpos, vpos);
844   double pos[2] = {vpos.GetX(), vpos.GetY()};
845 
846   double tolerance = 1.3;
847   double radius2 = this->ScreenPointRadius * this->ScreenPointRadius
848     * tolerance * tolerance;
849 
850   double screenPos[2];
851   this->Transform->TransformPoints(pos, screenPos, 1);
852   vtkIdType pointId = -1;
853   double minDist = VTK_DOUBLE_MAX;
854   const int numberOfPoints = this->GetNumberOfPoints();
855   for(vtkIdType i = 0; i < numberOfPoints; ++i)
856     {
857     double point[4];
858     this->GetControlPoint(i, point);
859     vtkVector2f vpos1(point[0], point[1]);
860     this->TransformDataToScreen(vpos1, vpos1);
861     point[0] = vpos1.GetX();
862     point[1] = vpos1.GetY();
863 
864     double screenPoint[2];
865     this->Transform->TransformPoints(point, screenPoint, 1);
866     double distance2 =
867       (screenPoint[0] - screenPos[0]) * (screenPoint[0] - screenPos[0]) +
868       (screenPoint[1] - screenPos[1]) * (screenPoint[1] - screenPos[1]);
869     if (distance2 <= radius2)
870       {
871       if (distance2 == 0.)
872         {// we found the best match ever
873         return i;
874         }
875       else if (distance2 < minDist)
876         {// we found something not too bad, maybe we can find closer
877         pointId = i;
878         minDist = distance2;
879         }
880       }
881     // don't search any further if the x is already too large
882     if (screenPoint[0] > (screenPos[0] + this->ScreenPointRadius * tolerance))
883       {
884       break;
885       }
886     }
887   return pointId;
888 }
889 
890 //-----------------------------------------------------------------------------
GetControlPointId(double * point)891 vtkIdType vtkControlPointsItem::GetControlPointId(double* point)
892 {
893   const int numberOfPoints = this->GetNumberOfPoints();
894   for(vtkIdType i = 0; i < numberOfPoints; ++i)
895     {
896     double controlPoint[4];
897     this->GetControlPoint(i, controlPoint);
898     if (controlPoint[0] == point[0])
899       {
900       return i;
901       }
902     }
903   return -1;
904 }
905 
906 //-----------------------------------------------------------------------------
907 void vtkControlPointsItem
GetControlPointsIds(vtkIdTypeArray * points,bool excludeFirstAndLast) const908 ::GetControlPointsIds(vtkIdTypeArray* points, bool excludeFirstAndLast)const
909 {
910   assert(points != 0);
911   int numberOfPoints = this->GetNumberOfPoints();
912   if (excludeFirstAndLast)
913     {
914     numberOfPoints -= 2;
915     }
916   numberOfPoints = std::max(numberOfPoints, 0);
917   points->SetNumberOfTuples(numberOfPoints);
918   vtkIdType pointId = excludeFirstAndLast ? 1 : 0;
919   for(vtkIdType i = 0; i < numberOfPoints; ++i)
920     {
921     points->SetValue(i, pointId++);
922     }
923 }
924 //-----------------------------------------------------------------------------
AddPointId(vtkIdType addedPointId)925 void vtkControlPointsItem::AddPointId(vtkIdType addedPointId)
926 {
927   assert(addedPointId != -1);
928   // offset all the point ids
929   const int selectionCount = this->GetNumberOfSelectedPoints();
930   for (vtkIdType i = 0; i < selectionCount; ++i)
931     {
932     vtkIdType pointId = this->Selection->GetValue(i);
933     if (pointId >= addedPointId)
934       {
935       this->Selection->SetValue(i, ++pointId);
936       }
937     }
938   if (this->CurrentPoint >= addedPointId)
939     {
940     this->SetCurrentPoint(this->CurrentPoint + 1);
941     }
942 }
943 
944 //-----------------------------------------------------------------------------
RemovePoint(double * point)945 vtkIdType vtkControlPointsItem::RemovePoint(double* point)
946 {
947   return this->RemovePointId(this->GetControlPointId(point));
948 }
949 
950 //-----------------------------------------------------------------------------
RemovePoint(vtkIdType pointId)951 vtkIdType vtkControlPointsItem::RemovePoint(vtkIdType pointId)
952 {
953   double point[4];
954   this->GetControlPoint(pointId, point);
955   return this->RemovePoint(point);
956 }
957 
958 //-----------------------------------------------------------------------------
RemovePointId(vtkIdType pointId)959 vtkIdType vtkControlPointsItem::RemovePointId(vtkIdType pointId)
960 {
961   if(!this->IsPointRemovable(pointId))
962     {
963     return pointId;
964     }
965 
966   this->StartChanges();
967 
968   assert(pointId != -1);
969   // Useless to remove the point here as it will be removed anyway in ComputePoints
970   this->DeselectPoint(pointId);
971 
972   const vtkIdType selectionCount = this->GetNumberOfSelectedPoints();
973   for (vtkIdType i = 0; i < selectionCount; ++i)
974     {
975     vtkIdType selectedPointId = this->Selection->GetValue(i);
976     if (selectedPointId > pointId)
977       {
978       this->Selection->SetValue(i, --selectedPointId);
979       }
980     }
981 
982   if (this->CurrentPoint > pointId ||
983       this->CurrentPoint == this->GetNumberOfPoints() - 1)
984     {
985     this->SetCurrentPoint(this->CurrentPoint - 1);
986     }
987 
988   this->EndChanges();
989   return pointId;
990 }
991 
992 //-----------------------------------------------------------------------------
SetCurrentPoint(vtkIdType index)993 void vtkControlPointsItem::SetCurrentPoint(vtkIdType index)
994 {
995   if (index == this->CurrentPoint)
996     {
997     return;
998     }
999   this->CurrentPoint = index;
1000   this->InvokeEvent(vtkControlPointsItem::CurrentPointChangedEvent,
1001                     reinterpret_cast<void *>(this->CurrentPoint));
1002   this->GetScene()->SetDirty(true);
1003 }
1004 
1005 //-----------------------------------------------------------------------------
MouseButtonPressEvent(const vtkContextMouseEvent & mouse)1006 bool vtkControlPointsItem::MouseButtonPressEvent(const vtkContextMouseEvent &mouse)
1007 {
1008   this->MouseMoved = false;
1009   this->PointToToggle = -1;
1010   this->PointToDelete = -1;
1011 
1012   vtkVector2f vpos = mouse.GetPos();
1013   this->TransformScreenToData(vpos, vpos);
1014   double pos[2];
1015   pos[0] = vpos.GetX();
1016   pos[1] = vpos.GetY();
1017   vtkIdType pointUnderMouse = this->FindPoint(pos);
1018 
1019   if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON)
1020     {
1021     if (pointUnderMouse != -1)
1022       {
1023       this->SetCurrentPoint(pointUnderMouse);
1024       return true;
1025       }
1026     else if (pointUnderMouse == -1
1027              && this->GetNumberOfSelectedPoints() <= 1
1028              && !this->StrokeMode)
1029       {
1030       this->ClampValidPos(pos);
1031       vtkIdType addedPoint = this->AddPoint(pos);
1032       this->SetCurrentPoint(addedPoint);
1033       return true;
1034       }
1035     else
1036       {
1037       this->SetCurrentPoint(-1);
1038       }
1039     return true;
1040     }
1041 
1042   if (mouse.GetButton() == vtkContextMouseEvent::RIGHT_BUTTON
1043       && pointUnderMouse != -1)
1044     {
1045     this->PointToToggle = pointUnderMouse;
1046     this->PointAboutToBeToggled = true;
1047     this->GetScene()->SetDirty(true);
1048     return true;
1049     }
1050 
1051   if (mouse.GetButton() == vtkContextMouseEvent::MIDDLE_BUTTON
1052       && pointUnderMouse != -1)
1053     {
1054     this->PointToDelete = pointUnderMouse;
1055     this->PointAboutToBeDeleted = true;
1056     this->GetScene()->SetDirty(true);
1057     return true;
1058     }
1059 
1060   return false;
1061 }
1062 
1063 //-----------------------------------------------------------------------------
MouseDoubleClickEvent(const vtkContextMouseEvent & mouse)1064 bool vtkControlPointsItem::MouseDoubleClickEvent(const vtkContextMouseEvent &mouse)
1065 {
1066   if (mouse.GetButton() == vtkContextMouseEvent::RIGHT_BUTTON)
1067     {
1068     if (this->Selection->GetNumberOfTuples())
1069       {
1070       this->DeselectAllPoints();
1071       }
1072     else
1073       {
1074       this->SelectAllPoints();
1075       }
1076     return true;
1077     }
1078   bool res = this->MouseButtonPressEvent(mouse);
1079   if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON
1080       && this->CurrentPoint != -1)
1081     {
1082     this->InvokeEvent(vtkControlPointsItem::CurrentPointEditEvent,
1083                       reinterpret_cast<void *>(this->CurrentPoint));
1084     }
1085   return res;
1086 }
1087 
1088 //-----------------------------------------------------------------------------
MouseMoveEvent(const vtkContextMouseEvent & mouse)1089 bool vtkControlPointsItem::MouseMoveEvent(const vtkContextMouseEvent &mouse)
1090 {
1091   vtkVector2f mousePos = mouse.GetPos();
1092   this->TransformScreenToData(mousePos, mousePos);
1093 
1094   if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON)
1095     {
1096     if (this->StrokeMode)
1097       {
1098       this->StartInteractionIfNotStarted();
1099 
1100       this->Stroke(mousePos);
1101 
1102       this->Interaction();
1103       }
1104     else if (this->CurrentPoint == -1 && this->GetNumberOfSelectedPoints() > 1)
1105       {
1106       vtkVector2f deltaPos = mouse.GetPos() - mouse.GetLastPos();
1107       if(this->IsEndPointPicked())
1108         {
1109         if(!this->GetEndPointsMovable())
1110           {
1111           return false;
1112           }
1113         else if(this->GetEndPointsXMovable())
1114           {
1115           deltaPos.SetY(0);
1116           }
1117         else if(this->GetEndPointsYMovable())
1118           {
1119           deltaPos.SetX(0);
1120           }
1121         }
1122 
1123       this->StartInteractionIfNotStarted();
1124 
1125       if (vtkIdTypeArray* points = this->GetSelection())
1126         {
1127         // must stay valid after each individual point move
1128         points->Register(this);
1129         this->MovePoints(deltaPos, points);
1130         points->UnRegister(this);
1131         }
1132 
1133       this->Interaction();
1134       }
1135     else if (this->CurrentPoint != -1)
1136       {
1137       vtkVector2f curPos(mousePos);
1138       if(this->IsEndPointPicked())
1139         {
1140         double currentPoint[4] = {0.0, 0.0, 0.0, 0.0};
1141         this->GetControlPoint(this->CurrentPoint, currentPoint);
1142         if(!this->GetEndPointsMovable())
1143           {
1144           return false;
1145           }
1146         else if(this->GetEndPointsXMovable())
1147           {
1148           curPos.SetY(currentPoint[1]);
1149           }
1150         else if(this->GetEndPointsYMovable())
1151           {
1152           curPos.SetX(currentPoint[0]);
1153           }
1154         }
1155       this->StartInteractionIfNotStarted();
1156 
1157       this->SetCurrentPointPos(curPos);
1158 
1159       this->Interaction();
1160       }
1161     }
1162   if (mouse.GetButton() == vtkContextMouseEvent::RIGHT_BUTTON)
1163     {
1164     if (this->PointToToggle == -1)
1165       {
1166       return false;
1167       }
1168     double pos[2];
1169     pos[0] = mousePos[0];
1170     pos[1] = mousePos[1];
1171     vtkIdType pointUnderCursor = this->FindPoint(pos);
1172     if ((pointUnderCursor == this->PointToToggle) != this->PointAboutToBeToggled)
1173       {
1174       this->PointAboutToBeToggled = !this->PointAboutToBeToggled;
1175       this->GetScene()->SetDirty(true);
1176       }
1177     }
1178   this->MouseMoved = true;
1179   if (mouse.GetButton() == vtkContextMouseEvent::MIDDLE_BUTTON)
1180     {
1181     if (this->PointToDelete == -1)
1182       {
1183       // allow chart ruber band to work
1184       return false;
1185       }
1186     double pos[2];
1187     pos[0] = mousePos[0];
1188     pos[1] = mousePos[1];
1189     vtkIdType pointUnderCursor = this->FindPoint(pos);
1190     if ((pointUnderCursor == this->PointToDelete) != this->PointAboutToBeDeleted)
1191       {
1192       this->PointAboutToBeDeleted = !this->PointAboutToBeDeleted;
1193       this->GetScene()->SetDirty(true);
1194       }
1195     return true;
1196     }
1197 
1198   if (mouse.GetButton() == vtkContextMouseEvent::RIGHT_BUTTON
1199       && this->CurrentPoint == -1)
1200     {
1201     return false;
1202     }
1203   if (mouse.GetButton() == vtkContextMouseEvent::NO_BUTTON)
1204     {
1205     return false;
1206     }
1207   return true;
1208 }
1209 
1210 //-----------------------------------------------------------------------------
SetCurrentPointPos(const vtkVector2f & newPos)1211 void vtkControlPointsItem::SetCurrentPointPos(const vtkVector2f& newPos)
1212 {
1213   vtkIdType movedPoint = this->SetPointPos(this->CurrentPoint, newPos);
1214   // If the moved point was not CurrentPoint then make it current.
1215   this->SetCurrentPoint(movedPoint);
1216 }
1217 
1218 //-----------------------------------------------------------------------------
SetPointPos(vtkIdType point,const vtkVector2f & newPos)1219 vtkIdType vtkControlPointsItem::SetPointPos(vtkIdType point, const vtkVector2f& newPos)
1220 {
1221   if (point == -1)
1222     {
1223     return point;
1224     }
1225 
1226   // Make sure the new point is inside the boundaries of the function
1227   double boundedPos[2];
1228   boundedPos[0] = newPos[0];
1229   boundedPos[1] = newPos[1];
1230   this->ClampValidPos(boundedPos);
1231 
1232   if (!this->SwitchPointsMode)
1233     {
1234     // Stop mode.
1235     // You can't move a point past another point.
1236     if (point > 0)
1237       {
1238       double previousPoint[4] = {0.0, 0.0, 0.0, 0.0};
1239       this->GetControlPoint(point - 1, previousPoint);
1240       boundedPos[0] = std::max(previousPoint[0], boundedPos[0]);
1241       }
1242     if (point < this->GetNumberOfPoints() - 1)
1243       {
1244       double nextPoint[4] = {0.0, 0.0, 0.0, 0.0};
1245       this->GetControlPoint(point + 1, nextPoint);
1246       boundedPos[0] = std::min(boundedPos[0], nextPoint[0]);
1247       }
1248     }
1249   else
1250     {
1251     // Switch mode.
1252     // Moving a point to the right of the next one, makes it current.
1253     // and moving a point to the left of the previous one makes it current.
1254     if (point > 0)
1255       {
1256       double previousPoint[4] = {0.0, 0.0, 0.0, 0.0};
1257       this->GetControlPoint(point - 1, previousPoint);
1258       while (boundedPos[0] < previousPoint[0])
1259         {
1260         point = point - 1;
1261         if (point == 0)
1262           {
1263           break;
1264           }
1265         // maybe the move is that important that it went over multiple points
1266         this->GetControlPoint(point - 1, previousPoint);
1267         }
1268       }
1269     if (point < this->GetNumberOfPoints() - 1)
1270       {
1271       double nextPoint[4] = {0.0, 0.0, 0.0, 0.0};
1272       this->GetControlPoint(point + 1, nextPoint);
1273       while (boundedPos[0] > nextPoint[0])
1274         {
1275         point = point + 1;
1276         if (point == this->GetNumberOfPoints() - 1)
1277           {
1278           break;
1279           }
1280         this->GetControlPoint(point + 1, nextPoint);
1281         }
1282       }
1283     }
1284   double currentPoint[4] = {0.0, 0.0, 0.0, 0.0};
1285   this->GetControlPoint(point, currentPoint);
1286   currentPoint[0] = boundedPos[0];
1287   currentPoint[1] = boundedPos[1];
1288 
1289   // SetControlPoint will call StartChanges/EndChanges correctly, so we don't
1290   // need to call it here.
1291   this->SetControlPoint(point, currentPoint);
1292   return point;
1293 }
1294 
1295 //-----------------------------------------------------------------------------
MoveCurrentPoint(const vtkVector2f & translation)1296 void vtkControlPointsItem::MoveCurrentPoint(const vtkVector2f& translation)
1297 {
1298   this->MovePoint(this->CurrentPoint, translation);
1299 }
1300 
1301 //-----------------------------------------------------------------------------
MovePoint(vtkIdType pointId,const vtkVector2f & translation)1302 vtkIdType vtkControlPointsItem::MovePoint(vtkIdType pointId, const vtkVector2f& translation)
1303 {
1304   double point[4];
1305   this->GetControlPoint(pointId, point);
1306   return this->SetPointPos(pointId, vtkVector2f(point[0] + translation.GetX(), point[1] + translation.GetY()));
1307 }
1308 
1309 //-----------------------------------------------------------------------------
MovePoints(const vtkVector2f & translation,vtkIdTypeArray * pointIds)1310 void vtkControlPointsItem::MovePoints(const vtkVector2f& translation, vtkIdTypeArray* pointIds)
1311 {
1312   assert(pointIds);
1313   this->StartChanges();
1314   // don't support 'switch' mode yet
1315   //vtkIdTypeArray* addedSelection = vtkIdTypeArray::New();
1316   bool oldSwitchPoints = this->SwitchPointsMode;
1317   this->SwitchPointsMode = false;
1318   // end "don't support 'switch' mode yet"
1319   const int count = pointIds->GetNumberOfTuples();
1320   float tX = translation.GetX();
1321   float tY = translation.GetY();
1322   int start = tX < 0.f ? 0 : count - 1;
1323   int end = tX < 0.f ? count : -1;
1324   int step = tX < 0.f ? 1 : -1;
1325   for (vtkIdType i = start; i != end; i+=step)
1326     {
1327     vtkIdType pointId = pointIds->GetValue(i);
1328     double currentPoint[4] = {0.0, 0.0, 0.0, 0.0};
1329     this->GetControlPoint(pointId, currentPoint);
1330     vtkVector2f newPos(currentPoint[0] + tX, currentPoint[1] + tY);
1331     //vtkIdType newIdx =
1332       this->SetPointPos(pointId, newPos);
1333     // don't support 'switch' mode yet
1334     //if (newIdx != point)
1335     //  {
1336     //  int next = (newIdx > point) ? 1 : -1;
1337     //  for (int i = point + next; i != newIdx; i+=next)
1338     //    {
1339     //    addedSelection->InsertNextValue(i);
1340     //    }
1341     //  addedSelection->InsertNextValue(newIdx);
1342     //  }
1343     // end "don't support 'switch' mode yet"
1344     }
1345   // don't support 'switch' mode yet
1346   //this->SelectPoints(addedSelection);
1347   this->SwitchPointsMode = oldSwitchPoints;
1348   // end "don't support 'switch' mode yet"
1349   this->EndChanges();
1350 }
1351 
1352 //-----------------------------------------------------------------------------
MovePoints(const vtkVector2f & translation,bool dontMoveFirstAndLast)1353 void vtkControlPointsItem::MovePoints(const vtkVector2f& translation,
1354                                       bool dontMoveFirstAndLast)
1355 {
1356   vtkNew<vtkIdTypeArray> points;
1357   this->GetControlPointsIds(points.GetPointer(), dontMoveFirstAndLast);
1358   this->MovePoints(translation, points.GetPointer());
1359 }
1360 
1361 //-----------------------------------------------------------------------------
SpreadPoints(float factor,vtkIdTypeArray * pointIds)1362 void vtkControlPointsItem::SpreadPoints(float factor, vtkIdTypeArray* pointIds)
1363 {
1364   assert(pointIds);
1365   if (pointIds->GetNumberOfTuples() == 0)
1366     {
1367     return;
1368     }
1369   this->StartChanges();
1370 
1371   double min[2], max[2], center[2];
1372   double point[4];
1373   vtkIdType minPointId = pointIds->GetValue(0);
1374   this->GetControlPoint(minPointId, point);
1375   min[0] = point[0];
1376   min[1] = point[1];
1377   vtkIdType maxPointId = pointIds->GetValue(pointIds->GetNumberOfTuples() - 1);
1378   this->GetControlPoint(maxPointId, point);
1379   max[0] = point[0];
1380   max[1] = point[1];
1381   center[0] = (min[0] + max[0]) / 2.;
1382   center[1] = (min[1] + max[1]) / 2.;
1383 
1384   // Left part
1385   vtkIdType start = 0;
1386   vtkIdType end = pointIds->GetNumberOfTuples();
1387   vtkIdType step = 1;
1388   vtkIdType median = -1; // not needed when factor >= 0
1389   if (factor < 0.f)
1390     {
1391     // search median
1392     for (vtkIdType i = 0; i < end; ++i)
1393       {
1394       vtkIdType pointId = pointIds->GetValue(i);
1395       this->GetControlPoint(pointId, point);
1396       if (point[0] > center[0])
1397         {
1398         median = i;
1399         break;
1400         }
1401       }
1402     if (median == -1)
1403       {
1404       median = pointIds->GetNumberOfTuples() - 1;
1405       }
1406     start = median - 1;
1407     end = -1;
1408     step = -1;
1409     }
1410   vtkIdType i;
1411   for (i = start; i != end; i+=step)
1412     {
1413     vtkIdType pointId = pointIds->GetValue(i);
1414     this->GetControlPoint(pointId, point);
1415     if (point[0] > center[0] ||
1416         (i != start && point[0] == center[0]))
1417       {
1418       break;
1419       }
1420     double tX = -factor;
1421     tX *= (min[0] != center[0]) ?
1422       (center[0] - point[0]) / (center[0] - min[0]) :
1423       fabs(point[0]) / 100.;
1424     vtkVector2f newPos(std::min(point[0] + tX, center[0]), point[1]);
1425     this->SetPointPos(pointId, newPos);
1426     }
1427   // Right part
1428   start = pointIds->GetNumberOfTuples() - 1;
1429   end = i - 1;
1430   step = -1;
1431   if (factor < 0.f)
1432     {
1433     start = median;
1434     end = pointIds->GetNumberOfTuples();
1435     step = 1;
1436     }
1437   for (i = start; i != end; i+=step)
1438     {
1439     vtkIdType pointId = pointIds->GetValue(i);
1440     this->GetControlPoint(pointId, point);
1441     assert(point[0] >= center[0]);
1442     double tX = factor;
1443     tX *= (max[0] != center[0]) ?
1444       (point[0] - center[0]) / (max[0] - center[0]) :
1445       fabs(point[0]) / 100.;
1446     vtkVector2f newPos(std::max(point[0] + tX, center[0]), point[1]);
1447     this->SetPointPos(pointId, newPos);
1448     }
1449   this->EndChanges();
1450 }
1451 
1452 //-----------------------------------------------------------------------------
SpreadPoints(float factor,bool dontSpreadFirstAndLast)1453 void vtkControlPointsItem::SpreadPoints(float factor, bool dontSpreadFirstAndLast)
1454 {
1455   vtkNew<vtkIdTypeArray> points;
1456   this->GetControlPointsIds(points.GetPointer(), dontSpreadFirstAndLast);
1457   this->SpreadPoints(factor, points.GetPointer());
1458 }
1459 
1460 //-----------------------------------------------------------------------------
GetCenterOfMass(vtkIdTypeArray * pointIDs) const1461 vtkVector2f vtkControlPointsItem::GetCenterOfMass(vtkIdTypeArray* pointIDs)const
1462 {
1463   double average[4] = {0., 0., 0., 0.};
1464   const vtkIdType pointCount = pointIDs->GetNumberOfTuples();
1465   for (vtkIdType i = 0; i < pointCount; ++i)
1466     {
1467     double point[4];
1468     this->GetControlPoint(pointIDs->GetValue(i), point);
1469     average[0] += point[0]; // x
1470     average[1] += point[1]; // y
1471     average[2] += point[2]; // midpoint
1472     average[3] += point[3]; // sharpness
1473     }
1474   average[0] /= pointCount; // x
1475   average[1] /= pointCount; // y
1476   average[2] /= pointCount; // midpoint
1477   average[3] /= pointCount; // sharpness
1478   return vtkVector2f(average[0], average[1]);
1479 }
1480 
1481 //-----------------------------------------------------------------------------
Stroke(const vtkVector2f & newPos)1482 void vtkControlPointsItem::Stroke(const vtkVector2f& newPos)
1483 {
1484   double pos[2];
1485   pos[0] = newPos[0];
1486   pos[1] = newPos[1];
1487   this->ClampValidPos(pos);
1488 
1489   // last point
1490   if (this->CurrentPoint != -1)
1491     {
1492     vtkIdType lastPointId = this->CurrentPoint;
1493     double lastPoint[4] = {0.0, 0.0, 0.0, 0.0};
1494     this->GetControlPoint(lastPointId, lastPoint);
1495     const double pointSpacing = 1.15;
1496     float oldScreenPointRadius = this->ScreenPointRadius;
1497     this->ScreenPointRadius *= pointSpacing;
1498     // ignore the stroke if it is too close from the last point
1499     if (this->FindPoint(pos) == lastPointId)
1500       {
1501       this->ScreenPointRadius = oldScreenPointRadius;
1502       return;
1503       }
1504     this->ScreenPointRadius = oldScreenPointRadius;
1505     // For the first case or when the new pos share the same X (but not the
1506     // same y) then we just have to modify the last point
1507     if (!this->MouseMoved || lastPoint[0] == pos[0])
1508       {
1509       lastPoint[0] = pos[0];
1510       lastPoint[1] = pos[1];
1511       this->SetControlPoint(this->CurrentPoint, lastPoint);
1512       return;
1513       }
1514     assert(lastPoint[0] != pos[0]);
1515     // CurrentPoint != -1 && MouseMoved
1516     // Starting from the last point, we search points (forward or backward) to see
1517     // if there are points that can be removed.
1518     int count = this->GetNumberOfPoints();
1519     if (pos[0] > lastPoint[0] && lastPointId < count - 1)
1520       {
1521       // search if there are points between pos and lastPoint
1522       double point[4] = {0.0, 0.0, 0.0, 0.0};
1523       this->GetControlPoint(lastPointId + 1, point);
1524       while (pos[0] >= point[0])
1525         {
1526         this->RemovePoint(point);
1527         count = this->GetNumberOfPoints();
1528         if (lastPointId == count - 1)
1529            {
1530            break;
1531            }
1532         this->GetControlPoint(lastPointId + 1, point);
1533         }
1534       }
1535     else if (pos[0] < lastPoint[0] && lastPointId > 0)
1536       {
1537       // search if there are points between pos and lastPoint
1538       double point[4] = {0.0, 0.0, 0.0, 0.0};
1539       this->GetControlPoint(lastPointId - 1, point);
1540       while (pos[0] <= point[0])
1541         {
1542         this->RemovePoint(point);
1543         --lastPointId;
1544         if (lastPointId == 0)
1545            {
1546            break;
1547            }
1548         this->GetControlPoint(lastPointId - 1, point);
1549         }
1550       }
1551     }
1552 #ifndef NDEBUG
1553   const int oldNumberOfPoints = this->GetNumberOfPoints();
1554 #endif
1555   vtkIdType addedPoint = this->AddPoint(pos);
1556   this->SetCurrentPoint(addedPoint);
1557   assert(oldNumberOfPoints + 1 == this->GetNumberOfPoints());
1558 }
1559 
1560 //-----------------------------------------------------------------------------
EditPoint(float vtkNotUsed (tX),float vtkNotUsed (tY))1561 void vtkControlPointsItem::EditPoint(float vtkNotUsed(tX), float vtkNotUsed(tY))
1562 {
1563 }
1564 
1565 //-----------------------------------------------------------------------------
MouseButtonReleaseEvent(const vtkContextMouseEvent & mouse)1566 bool vtkControlPointsItem::MouseButtonReleaseEvent(const vtkContextMouseEvent &mouse)
1567 {
1568   if (this->GetInteractionsCount())
1569     {
1570     this->EndInteraction();
1571     }
1572   if (mouse.GetButton() == vtkContextMouseEvent::LEFT_BUTTON)
1573     {
1574     return true;
1575     }
1576   if (mouse.GetButton() == vtkContextMouseEvent::RIGHT_BUTTON
1577       && this->PointToToggle != -1)
1578     {
1579     if (this->PointAboutToBeToggled)
1580       {
1581       this->ToggleSelectPoint(this->PointToToggle);
1582       this->PointToToggle = -1;
1583       this->PointAboutToBeToggled = false;
1584       }
1585     return true;
1586     }
1587   if (mouse.GetButton() == vtkContextMouseEvent::MIDDLE_BUTTON
1588       && this->PointToDelete != -1)
1589     {
1590     if (this->PointAboutToBeDeleted)
1591       {
1592       // If EnforceValidFunction is true, we don't want less than 2 points
1593       if (this->IsPointRemovable(this->PointToDelete))
1594         {
1595         double point[4];
1596         this->GetControlPoint(this->PointToDelete, point);
1597         this->RemovePoint(point);
1598         this->PointToDelete = -1;
1599         this->PointAboutToBeDeleted = false;
1600         }
1601       else
1602         {
1603         this->PointToDelete = -1;
1604         this->PointAboutToBeDeleted = false;
1605         this->GetScene()->SetDirty(true);
1606         }
1607       }
1608     return true;
1609     }
1610   return false;
1611 }
1612 
1613 //-----------------------------------------------------------------------------
KeyPressEvent(const vtkContextKeyEvent & key)1614 bool vtkControlPointsItem::KeyPressEvent(const vtkContextKeyEvent &key)
1615 {
1616   bool move = key.GetInteractor()->GetAltKey() != 0 ||
1617               key.GetInteractor()->GetKeySym() == vtkStdString("plus") ||
1618               key.GetInteractor()->GetKeySym() == vtkStdString("minus");
1619   bool select = !move && key.GetInteractor()->GetShiftKey() != 0;
1620   bool control = key.GetInteractor()->GetControlKey() != 0;
1621   bool current = !select && !move && !control;
1622   if (current)
1623     {
1624     if (key.GetInteractor()->GetKeySym() == vtkStdString("Right") ||
1625         key.GetInteractor()->GetKeySym() == vtkStdString("Up"))
1626       {
1627       this->SetCurrentPoint(
1628         std::min(this->GetNumberOfPoints() -1, this->GetCurrentPoint() + 1));
1629       }
1630     else if (key.GetInteractor()->GetKeySym() == vtkStdString("Left") ||
1631              key.GetInteractor()->GetKeySym() == vtkStdString("Down"))
1632       {
1633       this->SetCurrentPoint(
1634         std::max(0, static_cast<int>(this->GetCurrentPoint()) - 1));
1635       }
1636     else if (key.GetInteractor()->GetKeySym() == vtkStdString("End"))
1637       {
1638       this->SetCurrentPoint(this->GetNumberOfPoints() - 1);
1639       }
1640     else if (key.GetInteractor()->GetKeySym() == vtkStdString("Home"))
1641       {
1642       this->SetCurrentPoint(0);
1643       }
1644     }
1645   else if (select)
1646     {
1647     if (key.GetInteractor()->GetKeySym() == std::string("Right") ||
1648         key.GetInteractor()->GetKeySym() == std::string("Up"))
1649       {
1650       this->SelectPoint(this->CurrentPoint);
1651       this->SetCurrentPoint(
1652         std::min(this->GetNumberOfPoints() -1, this->GetCurrentPoint() + 1));
1653       this->SelectPoint(this->CurrentPoint);
1654       }
1655     else if (key.GetInteractor()->GetKeySym() == std::string("Left") ||
1656              key.GetInteractor()->GetKeySym() == std::string("Down"))
1657       {
1658       this->SelectPoint(this->CurrentPoint);
1659       this->SetCurrentPoint(
1660         std::max(0, static_cast<int>(this->GetCurrentPoint()) - 1));
1661       this->SelectPoint(this->CurrentPoint);
1662       }
1663     else if (key.GetInteractor()->GetKeySym() == vtkStdString("End"))
1664       {
1665       vtkIdType newCurrentPointId = this->GetNumberOfPoints() - 1;
1666       for (vtkIdType pointId = this->CurrentPoint; pointId < newCurrentPointId; ++pointId)
1667         {
1668         this->SelectPoint(pointId);
1669         }
1670       this->SelectPoint(newCurrentPointId);
1671       this->SetCurrentPoint(newCurrentPointId);
1672       }
1673     else if (key.GetInteractor()->GetKeySym() == vtkStdString("Home"))
1674       {
1675       vtkIdType newCurrentPointId = 0;
1676       for (vtkIdType pointId = this->CurrentPoint; pointId > newCurrentPointId; --pointId)
1677         {
1678         this->SelectPoint(pointId);
1679         }
1680       this->SelectPoint(newCurrentPointId);
1681       this->SetCurrentPoint(newCurrentPointId);
1682       }
1683     }
1684   else if (move)
1685     {
1686     vtkVector2f translate(0,0);
1687     if (key.GetInteractor()->GetKeySym() == std::string("Up"))
1688       {
1689       translate = translate + vtkVector2f(0., 1.);
1690       }
1691     if (key.GetInteractor()->GetKeySym() == std::string("Down"))
1692       {
1693       translate = translate + vtkVector2f(0., -1.);
1694       }
1695     if (key.GetInteractor()->GetKeySym() == std::string("Right"))
1696       {
1697       translate = translate + vtkVector2f(1., 0.);
1698       }
1699     if (key.GetInteractor()->GetKeySym() == std::string("Left"))
1700       {
1701       translate = translate + vtkVector2f(-1., 0.);
1702       }
1703     if (translate.GetX() != 0.f || translate.GetY() != 0.f)
1704       {
1705       double bounds[4];
1706       this->GetBounds(bounds);
1707       float step = control ? 0.001 : 0.01;
1708       translate.SetX( translate.GetX() * (bounds[1] - bounds[0]) * step);
1709       translate.SetY( translate.GetY() * (bounds[3] - bounds[2]) * step);
1710       if (this->GetNumberOfSelectedPoints())
1711         {
1712         this->StartInteractionIfNotStarted();
1713 
1714         if (vtkIdTypeArray* points = this->GetSelection())
1715           {
1716           points->Register(this); // must stay valid after each individual move
1717           this->MovePoints(translate, points);
1718           points->UnRegister(this);
1719           }
1720 
1721         this->Interaction();
1722         }
1723       else
1724         {
1725         this->StartInteractionIfNotStarted();
1726 
1727         this->MoveCurrentPoint(translate);
1728 
1729         this->Interaction();
1730         }
1731       }
1732     else if (key.GetInteractor()->GetKeySym() == std::string("plus"))
1733       {
1734       this->StartInteractionIfNotStarted();
1735 
1736       if (vtkIdTypeArray* pointIds = this->GetSelection())
1737         {
1738         pointIds->Register(this); // must stay valid after each individual move
1739         this->SpreadPoints(1., pointIds);
1740         pointIds->UnRegister(this);
1741         }
1742 
1743       this->Interaction();
1744       }
1745     else if (key.GetInteractor()->GetKeySym() == std::string("minus"))
1746       {
1747       this->StartInteractionIfNotStarted();
1748 
1749       if (vtkIdTypeArray* pointIds = this->GetSelection())
1750         {
1751         pointIds->Register(this); // must stay valid after each individual move
1752         this->SpreadPoints(-1., pointIds);
1753         pointIds->UnRegister(this);
1754         }
1755 
1756       this->Interaction();
1757       }
1758     }
1759   else if (control)
1760     {
1761     if (key.GetInteractor()->GetKeySym() == std::string("a"))
1762       {
1763       this->SelectAllPoints();
1764       }
1765     }
1766   if (key.GetInteractor()->GetKeySym() == vtkStdString("space"))
1767     {
1768     this->ToggleSelectPoint(this->GetCurrentPoint());
1769     }
1770   else if (key.GetInteractor()->GetKeySym() == vtkStdString("Escape"))
1771     {
1772     this->DeselectAllPoints();
1773     }
1774   return this->Superclass::KeyPressEvent(key);
1775 }
1776 
1777 //-----------------------------------------------------------------------------
KeyReleaseEvent(const vtkContextKeyEvent & key)1778 bool vtkControlPointsItem::KeyReleaseEvent(const vtkContextKeyEvent &key)
1779 {
1780   if (key.GetInteractor()->GetKeySym() == std::string("Delete") ||
1781       key.GetInteractor()->GetKeySym() == std::string("BackSpace"))
1782     {
1783     vtkIdType removedPoint = this->RemovePoint(this->GetCurrentPoint());
1784     if (key.GetInteractor()->GetKeySym() == std::string("BackSpace"))
1785       {
1786       this->SetCurrentPoint(removedPoint > 0 ? removedPoint - 1 : 0);
1787       }
1788     return true;
1789     }
1790   return this->Superclass::KeyPressEvent(key);
1791 }
1792 
1793 //-----------------------------------------------------------------------------
GetEndPointsMovable()1794 bool vtkControlPointsItem::GetEndPointsMovable()
1795 {
1796   return (this->GetEndPointsXMovable() || this->GetEndPointsYMovable());
1797 }
1798 
1799 //-----------------------------------------------------------------------------
IsEndPointPicked()1800 bool vtkControlPointsItem::IsEndPointPicked()
1801 {
1802   int numPts = this->GetNumberOfPoints();
1803   if(numPts<=0)
1804     {
1805     return false;
1806     }
1807   if(this->CurrentPoint==0 || this->CurrentPoint==numPts-1)
1808     {
1809     return true;
1810     }
1811   vtkIdTypeArray* selection = this->GetSelection();
1812   if(selection && selection->GetNumberOfTuples()>0)
1813     {
1814     vtkIdType pid;
1815     for (vtkIdType i = 0; i < selection->GetNumberOfTuples(); ++i)
1816       {
1817       pid=selection->GetValue(i);
1818       if(pid==0 || pid==numPts-1)
1819         {
1820         return true;
1821         }
1822       }
1823     }
1824   return false;
1825 }
1826 
1827 //-----------------------------------------------------------------------------
IsPointRemovable(vtkIdType pointId)1828 bool vtkControlPointsItem::IsPointRemovable(vtkIdType pointId)
1829 {
1830   vtkIdType numPts = this->GetNumberOfPoints();
1831   if (this->EnforceValidFunction && numPts<= 2)
1832     {
1833     return false;
1834     }
1835   if(pointId != -1 && !this->GetEndPointsRemovable() &&
1836     (pointId==0 || pointId==numPts-1))
1837     {
1838     return false;
1839     }
1840   return true;
1841 }
1842 
1843 //-----------------------------------------------------------------------------
GetControlPointLabel(vtkIdType pointId)1844 vtkStdString vtkControlPointsItem::GetControlPointLabel(vtkIdType pointId)
1845 {
1846   vtkStdString result;
1847   if (this->LabelFormat)
1848     {
1849     char *buffer = new char[1024];
1850     double point[4];
1851     this->GetControlPoint(pointId, point);
1852     sprintf(buffer, this->LabelFormat, point[0], point[1], point[2], point[3]);
1853     result = buffer;
1854     delete []buffer;
1855     }
1856   return result;
1857 }
1858