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