1 /*========================================================================= 2 3 Program: Visualization Toolkit 4 Module: vtkControlPointsItem.h 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 /** 17 * @class vtkControlPointsItem 18 * @brief Abstract class for control points items. 19 * 20 * vtkControlPointsItem provides control point painting and management for 21 * subclasses that provide points (typically control points of a transfer 22 * function) 23 * @sa 24 * vtkScalarsToColorsItem 25 * vtkPiecewiseControlPointsItem 26 */ 27 28 #ifndef vtkControlPointsItem_h 29 #define vtkControlPointsItem_h 30 31 #include "vtkPlot.h" 32 33 #include "vtkChartsCoreModule.h" // For export macro 34 #include "vtkCommand.h" // For vtkCommand enum 35 #include "vtkSmartPointer.h" // For SmartPointer 36 #include "vtkVector.h" // For vtkVector2f 37 #include <string> // Used by GetControlPointLabel 38 39 class vtkCallbackCommand; 40 class vtkContext2D; 41 class vtkControlPointsAddPointItem; 42 class vtkPiecewisePointHandleItem; 43 class vtkPoints2D; 44 class vtkTransform2D; 45 46 class VTKCHARTSCORE_EXPORT vtkControlPointsItem : public vtkPlot 47 { 48 public: 49 vtkTypeMacro(vtkControlPointsItem, vtkPlot); 50 void PrintSelf(ostream& os, vtkIndent indent) override; 51 52 // Events fires by this class (and subclasses). 53 // \li CurrentPointChangedEvent is fired when the current point index is changed. 54 // \li CurrentPointEditEvent is fired to request the application to show UI to 55 // edit the current point. 56 // \li vtkCommand::StartEvent and vtkCommand::EndEvent is fired 57 // to mark groups of changes to control points. 58 enum 59 { 60 CurrentPointChangedEvent = vtkCommand::UserEvent, 61 CurrentPointEditEvent 62 }; 63 64 /** 65 * Bounds of the item, typically the bound of all the control points 66 * except if custom bounds have been set \sa SetUserBounds. 67 */ 68 void GetBounds(double bounds[4]) override; 69 70 ///@{ 71 /** 72 * Set custom bounds, except if bounds are invalid, bounds will be 73 * automatically computed based on the range of the control points 74 * Invalid bounds by default. 75 */ 76 vtkSetVector4Macro(UserBounds, double); 77 vtkGetVector4Macro(UserBounds, double); 78 ///@} 79 80 ///@{ 81 /** 82 * Controls the valid range for the values. 83 * An invalid value (0, -1, 0., -1, 0, -1.) indicates that the valid 84 * range is the current bounds. It is the default behavior. 85 */ 86 vtkSetVector4Macro(ValidBounds, double); 87 vtkGetVector4Macro(ValidBounds, double); 88 ///@} 89 90 ///@{ 91 /** 92 * Get/set the radius for screen points. 93 * Default is 6.f 94 */ 95 vtkGetMacro(ScreenPointRadius, float); 96 vtkSetMacro(ScreenPointRadius, float); 97 ///@} 98 99 ///@{ 100 /** 101 * Get/Set the flag to draw points. 102 * Default is true. 103 */ 104 vtkGetMacro(DrawPoints, bool); 105 vtkSetMacro(DrawPoints, bool); 106 vtkBooleanMacro(DrawPoints, bool); 107 ///@} 108 109 /** 110 * Paint the points with a fixed size (cosmetic) which doesn't depend 111 * on the scene zoom factor. Selected and unselected points are drawn 112 * with a different color. 113 */ 114 bool Paint(vtkContext2D* painter) override; 115 116 /** 117 * Select a point by its ID 118 */ 119 void SelectPoint(vtkIdType pointId); 120 121 /** 122 * Utility function that selects a point providing its coordinates. 123 * To be found, the position of the point must be no further away than its 124 * painted point size 125 */ 126 void SelectPoint(double* currentPoint); 127 128 /** 129 * Select all the points 130 */ 131 void SelectAllPoints(); 132 133 /** 134 * Unselect a point by its ID 135 */ 136 void DeselectPoint(vtkIdType pointId); 137 138 /** 139 * Utility function that unselects a point providing its coordinates. 140 * To be found, the position of the point must be no further away than its 141 * painted point size 142 */ 143 void DeselectPoint(double* currentPoint); 144 145 /** 146 * Unselect all the previously selected points 147 */ 148 void DeselectAllPoints(); 149 150 /** 151 * Toggle the selection of a point by its ID. If the point was selected then 152 * unselect it, otherwise select it. 153 */ 154 void ToggleSelectPoint(vtkIdType pointId); 155 156 /** 157 * Utility function that toggles the selection a point providing its 158 * coordinates. To be found, the position of the point must be no further 159 * away than its painted point size 160 */ 161 void ToggleSelectPoint(double* currentPoint); 162 163 /** 164 * Select all points in the specified rectangle. 165 */ 166 bool SelectPoints(const vtkVector2f& min, const vtkVector2f& max) override; 167 168 /** 169 * Return the number of selected points. 170 */ 171 vtkIdType GetNumberOfSelectedPoints() const; 172 173 /** 174 * Returns the vtkIdType of the point given its coordinates and a tolerance 175 * based on the screen point size. 176 */ 177 vtkIdType FindPoint(double* pos); 178 179 /** 180 * Returns true if pos is above the pointId point, false otherwise. 181 * It uses the size of the drawn point. To search what point is under the pos, 182 * use the more efficient \sa FindPoint() instead. 183 */ 184 bool IsOverPoint(double* pos, vtkIdType pointId); 185 186 /** 187 * Returns the id of the control point exactly matching pos, -1 if not found. 188 */ 189 vtkIdType GetControlPointId(double* pos); 190 191 /** 192 * Utility function that returns an array of all the control points IDs 193 * Typically: [0, 1, 2, ... n -1] where n is the point count 194 * Can exclude the first and last point ids from the array. 195 */ 196 void GetControlPointsIds(vtkIdTypeArray* ids, bool excludeFirstAndLast = false) const; 197 198 ///@{ 199 /** 200 * Controls whether or not control points are drawn (true) or clicked and 201 * moved (false). 202 * False by default. 203 */ 204 vtkSetMacro(StrokeMode, bool); 205 vtkGetMacro(StrokeMode, bool); 206 ///@} 207 208 ///@{ 209 /** 210 * If DrawPoints is false, SwitchPoints controls the behavior when a control 211 * point is dragged past another point. The crossed point becomes current 212 * (true) or the current point is blocked/stopped (false). 213 * False by default. 214 */ 215 vtkSetMacro(SwitchPointsMode, bool); 216 vtkGetMacro(SwitchPointsMode, bool); 217 ///@} 218 219 ///@{ 220 /** 221 * If EndPointsMovable is false, the two end points will not 222 * be moved. True by default. 223 */ 224 vtkSetMacro(EndPointsXMovable, bool); 225 vtkGetMacro(EndPointsXMovable, bool); 226 vtkSetMacro(EndPointsYMovable, bool); 227 vtkGetMacro(EndPointsYMovable, bool); 228 virtual bool GetEndPointsMovable(); 229 ///@} 230 231 ///@{ 232 /** 233 * If EndPointsRemovable is false, the two end points will not 234 * be removed. True by default. 235 */ 236 vtkSetMacro(EndPointsRemovable, bool); 237 vtkGetMacro(EndPointsRemovable, bool); 238 ///@} 239 240 ///@{ 241 /** 242 * When set to true, labels are shown on the current control point and the end 243 * points. Default is false. 244 */ 245 vtkSetMacro(ShowLabels, bool); 246 vtkGetMacro(ShowLabels, bool); 247 ///@} 248 249 ///@{ 250 /** 251 * Get/Set the label format. Default is "%.4f, %.4f". 252 */ 253 vtkSetStringMacro(LabelFormat); 254 vtkGetStringMacro(LabelFormat); 255 ///@} 256 257 /** 258 * Add a point to the function. Returns the index of the point (0 based), 259 * or -1 on error. 260 * Subclasses should reimplement this function to do the actual work. 261 */ 262 virtual vtkIdType AddPoint(double* newPos) = 0; 263 264 /** 265 * Remove a point of the function. Returns the index of the point (0 based), 266 * or -1 on error. 267 * Subclasses should reimplement this function to do the actual work. 268 */ 269 virtual vtkIdType RemovePoint(double* pos) = 0; 270 271 /** 272 * Remove a point give its id. It is a utility function that internally call 273 * the virtual method RemovePoint(double*) and return its result. 274 */ 275 vtkIdType RemovePoint(vtkIdType pointId); 276 277 /** 278 * Remove the current point. 279 */ 280 void RemoveCurrentPoint(); 281 282 /** 283 * Returns the total number of points 284 */ 285 virtual vtkIdType GetNumberOfPoints() const = 0; 286 287 /** 288 * Returns the x and y coordinates as well as the midpoint and sharpness 289 * of the control point corresponding to the index. 290 * point must be a double array of size 4. 291 */ 292 virtual void GetControlPoint(vtkIdType index, double* point) const = 0; 293 294 /** 295 * Sets the x and y coordinates as well as the midpoint and sharpness 296 * of the control point corresponding to the index. 297 */ 298 virtual void SetControlPoint(vtkIdType index, double* point) = 0; 299 300 /** 301 * Move the points referred by pointIds by a given translation. 302 * The new positions won't be outside the bounds. 303 * MovePoints is typically called with GetControlPointsIds() or GetSelection(). 304 * Warning: if you pass this->GetSelection(), the array is deleted after 305 * each individual point move. Increase the reference count of the array. 306 * See also MoveAllPoints() 307 */ 308 void MovePoints(const vtkVector2f& translation, vtkIdTypeArray* pointIds); 309 310 /** 311 * Utility function to move all the control points of the given translation 312 * If dontMoveFirstAndLast is true, then the first and last points won't be 313 * moved. 314 */ 315 void MovePoints(const vtkVector2f& translation, bool dontMoveFirstAndLast = false); 316 317 /** 318 * Spread the points referred by pointIds 319 * If factor > 0, points are moved away from each other. 320 * If factor < 0, points are moved closer to each other 321 * SpreadPoints is typically called with GetControlPointsIds() or GetSelection(). 322 * Warning: if you pass this->GetSelection(), the array is deleted after 323 * each individual point move. Increase the reference count of the array. 324 */ 325 void SpreadPoints(float factor, vtkIdTypeArray* pointIds); 326 327 /** 328 * Utility function to spread all the control points of a given factor 329 * If dontSpreadFirstAndLast is true, then the first and last points won't be 330 * spread. 331 */ 332 void SpreadPoints(float factor, bool dontSpreadFirstAndLast = false); 333 334 /** 335 * Returns the current point ID selected or -1 if there is no point current. 336 * No current point by default. 337 */ 338 vtkIdType GetCurrentPoint() const; 339 340 /** 341 * Sets the current point selected. 342 */ 343 void SetCurrentPoint(vtkIdType index); 344 345 ///@{ 346 /** 347 * Gets the selected point pen and brush. 348 */ 349 vtkGetObjectMacro(SelectedPointPen, vtkPen); 350 ///@} 351 352 ///@{ 353 /** 354 * Depending on the control points item, the brush might not be taken into 355 * account. 356 */ 357 vtkGetObjectMacro(SelectedPointBrush, vtkBrush); 358 ///@} 359 360 ///@{ 361 /** 362 * When enabled, a dedicated item is used to determine if a point should 363 * be added when clicking anywhere. 364 * This item can be recovered with GetAddPointItem and can this be placed 365 * below all other items. False by default. 366 */ 367 vtkGetMacro(UseAddPointItem, bool); 368 vtkSetMacro(UseAddPointItem, bool); 369 vtkBooleanMacro(UseAddPointItem, bool); 370 ///@} 371 372 /** 373 * Item dedicated to add point, to be added below all other items. 374 * Used only if UseAddPointItem is set to true. 375 */ 376 vtkPlot* GetAddPointItem(); 377 378 /** 379 * Recompute the bounds next time they are requested. 380 * You shouldn't have to call it but it is provided for rare cases. 381 */ 382 void ResetBounds(); 383 384 ///@{ 385 /** 386 * Mouse and key events. 387 */ 388 bool MouseButtonPressEvent(const vtkContextMouseEvent& mouse) override; 389 bool MouseDoubleClickEvent(const vtkContextMouseEvent& mouse) override; 390 bool MouseButtonReleaseEvent(const vtkContextMouseEvent& mouse) override; 391 bool MouseMoveEvent(const vtkContextMouseEvent& mouse) override; 392 bool KeyPressEvent(const vtkContextKeyEvent& key) override; 393 bool KeyReleaseEvent(const vtkContextKeyEvent& key) override; 394 ///@} 395 396 protected: 397 vtkControlPointsItem(); 398 ~vtkControlPointsItem() override; 399 400 friend class vtkPiecewisePointHandleItem; 401 402 void StartChanges(); 403 void EndChanges(); 404 void StartInteraction(); 405 void StartInteractionIfNotStarted(); 406 void Interaction(); 407 void EndInteraction(); 408 int GetInteractionsCount() const; 409 virtual void emitEvent(unsigned long event, void* params = nullptr) = 0; 410 411 static void CallComputePoints( 412 vtkObject* sender, unsigned long event, void* receiver, void* params); 413 414 ///@{ 415 /** 416 * Must be reimplemented by subclasses to calculate the points to draw. 417 * It's subclass responsibility to call ComputePoints() via the callback 418 */ 419 virtual void ComputePoints(); 420 virtual vtkMTimeType GetControlPointsMTime() = 0; 421 ///@} 422 423 /** 424 * Returns true if the supplied x, y are within the bounds or on a control point. 425 * If UseAddPointItem is true, 426 * returns true only if the supplied x, y are on a control point. 427 */ 428 bool Hit(const vtkContextMouseEvent& mouse) override; 429 430 ///@{ 431 /** 432 * Clamp the given 2D pos into the bounds of the function. 433 * Return true if the pos has been clamped, false otherwise. 434 */ 435 bool ClampValidDataPos(double pos[2]); 436 bool ClampValidScreenPos(double pos[2]); 437 ///@} 438 439 ///@{ 440 /** 441 * Internal function that paints a collection of points and optionally 442 * excludes some. 443 */ 444 void DrawUnselectedPoints(vtkContext2D* painter); 445 void DrawSelectedPoints(vtkContext2D* painter); 446 virtual void DrawPoint(vtkContext2D* painter, vtkIdType index); 447 ///@} 448 449 void SetCurrentPointPos(const vtkVector2f& newPos); 450 vtkIdType SetPointPos(vtkIdType point, const vtkVector2f& newPos); 451 void MoveCurrentPoint(const vtkVector2f& translation); 452 vtkIdType MovePoint(vtkIdType point, const vtkVector2f& translation); 453 454 vtkVector2f GetSelectionCenterOfMass() const; 455 vtkVector2f GetCenterOfMass(vtkIdTypeArray* pointIDs) const; 456 457 void Stroke(const vtkVector2f& newPos); 458 virtual void EditPoint(float vtkNotUsed(tX), float vtkNotUsed(tY)); 459 460 /** 461 * Generate label for a control point. 462 */ 463 virtual std::string GetControlPointLabel(vtkIdType index); 464 465 void AddPointId(vtkIdType addedPointId); 466 467 /** 468 * Return true if any of the end points is current point 469 * or part of the selection 470 */ 471 bool IsEndPointPicked(); 472 473 /** 474 * Return true if the point is removable 475 */ 476 bool IsPointRemovable(vtkIdType pointId); 477 478 /** 479 * Compute the bounds for this item. Typically, the bounds should be aligned 480 * to the range of the vtkScalarsToColors or vtkPiecewiseFunction that is 481 * being controlled by the subclasses. 482 * Default implementation uses the range of the control points themselves. 483 */ 484 virtual void ComputeBounds(double* bounds); 485 486 vtkNew<vtkCallbackCommand> Callback; 487 vtkNew<vtkPen> SelectedPointPen; 488 vtkNew<vtkBrush> SelectedPointBrush; 489 int BlockUpdates = 0; 490 int StartedInteractions = 0; 491 int StartedChanges = 0; 492 vtkIdType CurrentPoint = -1; 493 494 double Bounds[4] = { 0., -1., 0., -1. }; 495 double UserBounds[4] = { 0., -1., 0., -1. }; 496 double ValidBounds[4] = { 0., -1., 0., -1. }; 497 498 vtkNew<vtkTransform2D> ControlPointsTransform; 499 float ScreenPointRadius = 6.f; 500 501 bool DrawPoints = true; 502 bool StrokeMode = false; 503 bool SwitchPointsMode = false; 504 bool MouseMoved = false; 505 bool EnforceValidFunction = true; 506 vtkIdType PointToDelete = -1; 507 bool PointAboutToBeDeleted = false; 508 vtkIdType PointToToggle = -1; 509 bool PointAboutToBeToggled = false; 510 bool InvertShadow = false; 511 bool EndPointsXMovable = true; 512 bool EndPointsYMovable = true; 513 bool EndPointsRemovable = true; 514 bool ShowLabels = false; 515 char* LabelFormat = nullptr; 516 517 private: 518 vtkControlPointsItem(const vtkControlPointsItem&) = delete; 519 void operator=(const vtkControlPointsItem&) = delete; 520 521 void ComputeBounds(); 522 523 vtkIdType RemovePointId(vtkIdType removedPointId); 524 525 bool UseAddPointItem = false; 526 vtkNew<vtkControlPointsAddPointItem> AddPointItem; 527 }; 528 #endif 529