vtkCompositeControlPointsItem.cxx 13.5 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkCompositeControlPointsItem.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/

#include "vtkBrush.h"
#include "vtkCallbackCommand.h"
#include "vtkContext2D.h"
#include "vtkIdTypeArray.h"
#include "vtkColorTransferFunction.h"
#include "vtkCompositeControlPointsItem.h"
#include "vtkObjectFactory.h"
#include "vtkPen.h"
#include "vtkPiecewiseFunction.h"
#include "vtkPoints2D.h"
#include "vtkContextScene.h"
27
#include "vtkPiecewisePointHandleItem.h"
28 29 30 31 32 33 34 35 36 37 38 39 40 41

// to handle mouse.GetButton
#include "vtkContextMouseEvent.h"

#include <cassert>
#include <limits>
#include <algorithm>

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkCompositeControlPointsItem);

//-----------------------------------------------------------------------------
vtkCompositeControlPointsItem::vtkCompositeControlPointsItem()
{
42
  this->PointsFunction = ColorAndOpacityPointsFunction;
43
  this->OpacityFunction = nullptr;
44
  this->ColorFill = true;
45
  this->OpacityPointHandle = nullptr;
46
  this->UseOpacityPointHandles = false;
47 48 49 50 51 52
}

//-----------------------------------------------------------------------------
vtkCompositeControlPointsItem::~vtkCompositeControlPointsItem()
{
  if (this->OpacityFunction)
53
  {
54
    this->OpacityFunction->RemoveObserver(this->Callback);
55
    this->OpacityFunction->Delete();
56
    this->OpacityFunction = nullptr;
57
  }
58
  if (this->OpacityPointHandle)
59
  {
60
    this->OpacityPointHandle->Delete();
61
    this->OpacityPointHandle = nullptr;
62
  }
63 64 65 66 67 68 69 70
}

//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::PrintSelf(ostream &os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os, indent);
  os << indent << "OpacityFunction: ";
  if (this->OpacityFunction)
71
  {
72 73
    os << endl;
    this->OpacityFunction->PrintSelf(os, indent.GetNextIndent());
74
  }
75
  else
76
  {
77
    os << "(none)" << endl;
78
  }
79 80
  os << indent << "OpacityFunction: ";
  if (this->OpacityPointHandle)
81
  {
82 83
    os << endl;
    this->OpacityPointHandle->PrintSelf(os, indent.GetNextIndent());
84
  }
85
  else
86
  {
87
    os << "(none)" << endl;
88
  }
89
  os << indent << "UseOpacityPointHandles: " << this->UseOpacityPointHandles << endl;
90 91
}

92
//-----------------------------------------------------------------------------
93
void vtkCompositeControlPointsItem::emitEvent(unsigned long event, void* params)
94 95
{
  if (this->OpacityFunction)
96
  {
97
    this->OpacityFunction->InvokeEvent(event, params);
98
  }
99
  this->Superclass::emitEvent(event, params);
100 101
}

102
//-----------------------------------------------------------------------------
103
vtkMTimeType vtkCompositeControlPointsItem::GetControlPointsMTime()
104
{
105
  vtkMTimeType mTime = this->Superclass::GetControlPointsMTime();
106
  if (this->OpacityFunction)
107
  {
108
    mTime = std::max(mTime, this->OpacityFunction->GetMTime());
109
  }
110
  return mTime;
111 112 113 114 115
}

//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::SetOpacityFunction(vtkPiecewiseFunction* function)
{
116
  if (function == this->OpacityFunction)
117
  {
118
    return;
119
  }
120
  if (this->OpacityFunction)
121
  {
122
    this->OpacityFunction->RemoveObserver(this->Callback);
123
  }
124
  vtkSetObjectBodyMacro(OpacityFunction, vtkPiecewiseFunction, function);
125
  if (this->PointsFunction == ColorAndOpacityPointsFunction)
126
  {
127
    this->SilentMergeTransferFunctions();
128
  }
129
  if (this->OpacityFunction)
130
  {
131
    this->OpacityFunction->AddObserver(vtkCommand::StartEvent, this->Callback);
132
    this->OpacityFunction->AddObserver(vtkCommand::ModifiedEvent, this->Callback);
133
    this->OpacityFunction->AddObserver(vtkCommand::EndEvent, this->Callback);
134
  }
135
  this->ResetBounds();
136 137 138 139 140 141
  this->ComputePoints();
}

//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::SetColorTransferFunction(vtkColorTransferFunction* c)
{
142
  if (c == this->ColorTransferFunction)
143
  {
144
    return;
145
  }
146 147 148 149
  // We need to set the color transfer function here (before
  // Superclass::SetPiecewiseFunction) to be able to have a valid
  // color transfer function for MergeColorTransferFunction().
  vtkSetObjectBodyMacro(ColorTransferFunction, vtkColorTransferFunction, c);
150
  if (this->PointsFunction == ColorAndOpacityPointsFunction)
151
  {
152
    this->SilentMergeTransferFunctions();
153
  }
154 155 156
  this->Superclass::SetColorTransferFunction(c);
}

157 158 159 160 161
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::DrawPoint(vtkContext2D* painter, vtkIdType index)
{
  if (this->PointsFunction == ColorPointsFunction ||
      this->PointsFunction == ColorAndOpacityPointsFunction)
162
  {
163 164
    this->Superclass::DrawPoint(painter, index);
    return;
165
  }
166 167
  if (this->PointsFunction == OpacityPointsFunction &&
      this->ColorFill && this->ColorTransferFunction)
168
  {
169 170
    double xvms[4];
    this->OpacityFunction->GetNodeValue(index, xvms);
171
    const unsigned char* rgb = this->ColorTransferFunction->MapValue(xvms[0]);
172 173
    painter->GetBrush()->SetColorF(
      rgb[0] / 255., rgb[1] / 255., rgb[2] / 255., 0.55);
174
  }
175 176 177 178
  this->vtkControlPointsItem::DrawPoint(painter, index);
}

//-----------------------------------------------------------------------------
179
vtkIdType vtkCompositeControlPointsItem::GetNumberOfPoints()const
180 181 182 183
{
  if (this->ColorTransferFunction &&
      (this->PointsFunction == ColorPointsFunction ||
       this->PointsFunction == ColorAndOpacityPointsFunction))
184
  {
185
    return this->Superclass::GetNumberOfPoints();
186
  }
187 188 189
  if (this->OpacityFunction &&
      (this->PointsFunction == OpacityPointsFunction ||
       this->PointsFunction == ColorAndOpacityPointsFunction))
190
  {
191
    return static_cast<vtkIdType>(this->OpacityFunction->GetSize());
192
  }
193 194 195
  return 0;
}

196 197 198
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::SetControlPoint(vtkIdType index, double* newPos)
{
199 200
  if (this->PointsFunction == ColorPointsFunction ||
      this->PointsFunction == ColorAndOpacityPointsFunction)
201
  {
202
    this->Superclass::SetControlPoint(index, newPos);
203
  }
204 205 206
  if (this->OpacityFunction &&
      (this->PointsFunction == OpacityPointsFunction ||
       this->PointsFunction == ColorAndOpacityPointsFunction))
207
  {
208
    this->StartChanges();
209
    this->OpacityFunction->SetNodeValue(index, newPos);
210
    this->EndChanges();
211
  }
212 213 214
}

//-----------------------------------------------------------------------------
215
void vtkCompositeControlPointsItem::GetControlPoint(vtkIdType index, double* pos)const
216
{
217 218
  if (!this->OpacityFunction ||
      this->PointsFunction == ColorPointsFunction)
219
  {
220
    this->Superclass::GetControlPoint(index, pos);
221
    if (this->OpacityFunction)
222
    {
223 224
      pos[1] = const_cast<vtkPiecewiseFunction*>(this->OpacityFunction)
        ->GetValue(pos[0]);
225
    }
226 227
    return;
  }
228 229
  const_cast<vtkPiecewiseFunction*>(this->OpacityFunction)
    ->GetNodeValue(index, pos);
230
}
231

232 233 234
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::EditPoint(float tX, float tY)
{
235 236
  if (this->PointsFunction == ColorPointsFunction ||
      this->PointsFunction == ColorAndOpacityPointsFunction)
237
  {
238
    this->Superclass::EditPoint(tX, tY);
239
  }
240 241 242
  if (this->OpacityFunction &&
      (this->PointsFunction == ColorPointsFunction ||
       this->PointsFunction == ColorAndOpacityPointsFunction))
243
  {
244
    this->StartChanges();
245 246
    double xvms[4];
    this->OpacityFunction->GetNodeValue(this->CurrentPoint, xvms);
247 248
    xvms[2] += tX;
    xvms[3] += tY;
249 250 251
    this->OpacityFunction->SetNodeValue(this->CurrentPoint, xvms);
    // Not sure why we move the point before too
    if (this->CurrentPoint > 0)
252
    {
253 254 255 256
      this->OpacityFunction->GetNodeValue(this->CurrentPoint - 1, xvms);
      xvms[2] += tX;
      xvms[3] += tY;
      this->OpacityFunction->SetNodeValue(this->CurrentPoint - 1, xvms);
257
    }
258 259
    this->EndChanges();
  }
260 261 262 263 264
}

//-----------------------------------------------------------------------------
vtkIdType vtkCompositeControlPointsItem::AddPoint(double* newPos)
{
265
  vtkIdType addedPoint = -1;
266
  this->StartChanges();
267 268 269
  if (this->OpacityFunction &&
      (this->PointsFunction == OpacityPointsFunction ||
       this->PointsFunction == ColorAndOpacityPointsFunction))
270
  {
271 272
    addedPoint = this->OpacityFunction->AddPoint(newPos[0], newPos[1]);
    if (this->PointsFunction == OpacityPointsFunction)
273
    {
274
      this->vtkControlPointsItem::AddPointId(addedPoint);
275
    }
276
  }
277 278
  if (this->PointsFunction == ColorPointsFunction ||
      this->PointsFunction == ColorAndOpacityPointsFunction)
279
  {
280
    addedPoint = this->Superclass::AddPoint(newPos);
281
  }
282
  this->EndChanges();
283
  return addedPoint;
284 285 286 287 288
}

//-----------------------------------------------------------------------------
vtkIdType vtkCompositeControlPointsItem::RemovePoint(double* currentPoint)
{
289
  vtkIdType removedPoint = -1;
290
  if (!this->IsPointRemovable(this->GetControlPointId(currentPoint)))
291
  {
292
    return removedPoint;
293
  }
294

295
  this->StartChanges();
296 297
  if (this->PointsFunction == ColorPointsFunction ||
      this->PointsFunction == ColorAndOpacityPointsFunction)
298
  {
299
    removedPoint = this->Superclass::RemovePoint(currentPoint);
300
  }
301 302 303
  if (this->OpacityFunction &&
      (this->PointsFunction == OpacityPointsFunction ||
       this->PointsFunction == ColorAndOpacityPointsFunction))
304
  {
305
    removedPoint = this->OpacityFunction->RemovePoint(currentPoint[0]);
306
  }
307
  this->EndChanges();
308
  return removedPoint;
309 310 311
}

//-----------------------------------------------------------------------------
312
void vtkCompositeControlPointsItem::MergeTransferFunctions()
313 314
{
  if (!this->ColorTransferFunction || !this->OpacityFunction)
315
  {
316
    return;
317
  }
318 319 320 321
  // Naive implementation that does the work but can be a bit slow
  // Copy OpacityFunction points into the ColorTransferFunction
  const int piecewiseFunctionCount = this->OpacityFunction->GetSize();
  for (int i = 0; i < piecewiseFunctionCount; ++i)
322
  {
323 324 325 326
    double piecewisePoint[4];
    this->OpacityFunction->GetNodeValue(i, piecewisePoint);
    double rgb[3];
    this->ColorTransferFunction->GetColor(piecewisePoint[0], rgb);
327
    // note that we might lose the midpoint/sharpness of the point if any
328 329
    this->ColorTransferFunction->RemovePoint(piecewisePoint[0]);
    this->ColorTransferFunction->AddRGBPoint(piecewisePoint[0], rgb[0], rgb[1], rgb[2], piecewisePoint[2], piecewisePoint[3]);
330
  }
331 332 333
  // Copy ColorTransferFunction points into the OpacityFunction
  const int colorFunctionCount = this->ColorTransferFunction->GetSize();
  for (int i = 0; i < colorFunctionCount; ++i)
334
  {
335 336 337
    double xrgbms[6];
    this->ColorTransferFunction->GetNodeValue(i, xrgbms);
    double value = this->OpacityFunction->GetValue(xrgbms[0]);
338
    // note that we might lose the midpoint/sharpness of the point if any
339 340
    this->OpacityFunction->RemovePoint(xrgbms[0]);
    this->OpacityFunction->AddPoint(xrgbms[0], value, xrgbms[4], xrgbms[5]);
341
  }
342
}
343

344 345 346
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::SilentMergeTransferFunctions()
{
347
  this->StartChanges();
348
  this->MergeTransferFunctions();
349
  this->EndChanges();
350
}
351 352 353 354 355 356

//-----------------------------------------------------------------------------
bool vtkCompositeControlPointsItem::MouseButtonPressEvent(const vtkContextMouseEvent &mouse)
{
  bool result=false;
  if(this->OpacityPointHandle && this->OpacityPointHandle->GetVisible())
357
  {
358
    result = this->OpacityPointHandle->MouseButtonPressEvent(mouse);
359
  }
360
  if(!result)
361
  {
362 363 364 365 366
    result = this->Superclass::MouseButtonPressEvent(mouse);
    if(result && this->OpacityPointHandle &&
     this->OpacityPointHandle->GetVisible() &&
     this->OpacityPointHandle->GetCurrentPointIndex() !=
     this->GetCurrentPoint())
367
    {
368 369
      this->OpacityPointHandle->SetVisible(false);
    }
370
  }
371 372 373 374 375 376 377 378
  return result;
}

//-----------------------------------------------------------------------------
bool vtkCompositeControlPointsItem::MouseDoubleClickEvent(const vtkContextMouseEvent &mouse)
{
   bool superRes = this->Superclass::MouseDoubleClickEvent(mouse);
   if(superRes)
379
   {
380 381
     vtkIdType curIdx = this->GetCurrentPoint();
     this->EditPointCurve(curIdx);
382
   }
383 384 385 386 387 388 389 390
   return superRes;
}

//-----------------------------------------------------------------------------
bool vtkCompositeControlPointsItem::MouseMoveEvent(const vtkContextMouseEvent &mouse)
{
  bool result=false;
  if(this->OpacityPointHandle && this->OpacityPointHandle->GetVisible())
391
  {
392
    result = this->OpacityPointHandle->MouseMoveEvent(mouse);
393
  }
394
  if(!result)
395
  {
396
    result = this->Superclass::MouseMoveEvent(mouse);
397
  }
398 399 400 401 402 403 404
  return result;
}

//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::EditPointCurve(vtkIdType index)
{
  if(index<0 || index>=this->GetNumberOfPoints())
405
  {
406
    return;
407
  }
408
  if(this->GetUseOpacityPointHandles())
409
  {
410
    if(!this->OpacityPointHandle)
411
    {
412 413 414 415
      this->OpacityPointHandle = vtkPiecewisePointHandleItem::New();
      this->AddItem(this->OpacityPointHandle);
      this->OpacityPointHandle->SetPiecewiseFunction(
        this->GetOpacityFunction());
416
    }
417
    else
418
    {
419 420 421 422
      this->OpacityPointHandle->SetVisible(
        !this->OpacityPointHandle->GetVisible());
      this->GetScene()->SetDirty(true);
    }
423
  }
424
}