vtkCompositeControlPointsItem.cxx 13.9 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 44
  this->OpacityFunction = 0;
  this->ColorFill = true;
45 46
  this->OpacityPointHandle = NULL;
  this->UseOpacityPointHandles = false;
47 48 49 50 51 52 53
}

//-----------------------------------------------------------------------------
vtkCompositeControlPointsItem::~vtkCompositeControlPointsItem()
{
  if (this->OpacityFunction)
    {
54
    this->OpacityFunction->RemoveObserver(this->Callback);
55 56 57
    this->OpacityFunction->Delete();
    this->OpacityFunction = 0;
    }
58 59 60 61 62
  if (this->OpacityPointHandle)
    {
    this->OpacityPointHandle->Delete();
    this->OpacityPointHandle = 0;
    }
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
}

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

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

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

//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::SetOpacityFunction(vtkPiecewiseFunction* function)
{
116 117 118 119
  if (function == this->OpacityFunction)
    {
    return;
    }
120 121 122 123
  if (this->OpacityFunction)
    {
    this->OpacityFunction->RemoveObserver(this->Callback);
    }
124
  vtkSetObjectBodyMacro(OpacityFunction, vtkPiecewiseFunction, function);
125 126 127 128
  if (this->PointsFunction == ColorAndOpacityPointsFunction)
    {
    this->SilentMergeTransferFunctions();
    }
129 130
  if (this->OpacityFunction)
    {
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 143 144 145
  if (c == this->ColorTransferFunction)
    {
    return;
    }
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 151 152 153
  if (this->PointsFunction == ColorAndOpacityPointsFunction)
    {
    this->SilentMergeTransferFunctions();
    }
154 155 156
  this->Superclass::SetColorTransferFunction(c);
}

157 158 159
//-----------------------------------------------------------------------------
bool vtkCompositeControlPointsItem::UsingLogScale()
{
160 161
  return (this->PointsFunction != OpacityPointsFunction &&
    this->ColorTransferFunction &&
162 163 164
    this->ColorTransferFunction->UsingLogScale());
}

165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::DrawPoint(vtkContext2D* painter, vtkIdType index)
{
  if (this->PointsFunction == ColorPointsFunction ||
      this->PointsFunction == ColorAndOpacityPointsFunction)
    {
    this->Superclass::DrawPoint(painter, index);
    return;
    }
  if (this->PointsFunction == OpacityPointsFunction &&
      this->ColorFill && this->ColorTransferFunction)
    {
    double xvms[4];
    this->OpacityFunction->GetNodeValue(index, xvms);
    unsigned char* rgb = this->ColorTransferFunction->MapValue(xvms[0]);
    painter->GetBrush()->SetColorF(
      rgb[0] / 255., rgb[1] / 255., rgb[2] / 255., 0.55);
    }
  this->vtkControlPointsItem::DrawPoint(painter, index);
}

//-----------------------------------------------------------------------------
187
vtkIdType vtkCompositeControlPointsItem::GetNumberOfPoints()const
188 189 190 191 192 193 194 195 196 197 198
{
  if (this->ColorTransferFunction &&
      (this->PointsFunction == ColorPointsFunction ||
       this->PointsFunction == ColorAndOpacityPointsFunction))
    {
    return this->Superclass::GetNumberOfPoints();
    }
  if (this->OpacityFunction &&
      (this->PointsFunction == OpacityPointsFunction ||
       this->PointsFunction == ColorAndOpacityPointsFunction))
    {
199
    return static_cast<vtkIdType>(this->OpacityFunction->GetSize());
200 201 202 203
    }
  return 0;
}

204 205 206
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::SetControlPoint(vtkIdType index, double* newPos)
{
207 208 209 210 211 212 213 214 215
  if (this->PointsFunction == ColorPointsFunction ||
      this->PointsFunction == ColorAndOpacityPointsFunction)
    {
    this->Superclass::SetControlPoint(index, newPos);
    }
  if (this->OpacityFunction &&
      (this->PointsFunction == OpacityPointsFunction ||
       this->PointsFunction == ColorAndOpacityPointsFunction))
    {
216
    this->StartChanges();
217
    this->OpacityFunction->SetNodeValue(index, newPos);
218
    this->EndChanges();
219
    }
220 221 222
}

//-----------------------------------------------------------------------------
223
void vtkCompositeControlPointsItem::GetControlPoint(vtkIdType index, double* pos)const
224
{
225 226
  if (!this->OpacityFunction ||
      this->PointsFunction == ColorPointsFunction)
227 228
    {
    this->Superclass::GetControlPoint(index, pos);
229 230
    if (this->OpacityFunction)
      {
231 232
      pos[1] = const_cast<vtkPiecewiseFunction*>(this->OpacityFunction)
        ->GetValue(pos[0]);
233
      }
234 235
    return;
    }
236 237
  const_cast<vtkPiecewiseFunction*>(this->OpacityFunction)
    ->GetNodeValue(index, pos);
238
}
239

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

//-----------------------------------------------------------------------------
vtkIdType vtkCompositeControlPointsItem::AddPoint(double* newPos)
{
273
  vtkIdType addedPoint = -1;
274
  this->StartChanges();
275 276 277
  if (this->OpacityFunction &&
      (this->PointsFunction == OpacityPointsFunction ||
       this->PointsFunction == ColorAndOpacityPointsFunction))
278
    {
279 280 281 282 283
    addedPoint = this->OpacityFunction->AddPoint(newPos[0], newPos[1]);
    if (this->PointsFunction == OpacityPointsFunction)
      {
      this->vtkControlPointsItem::AddPointId(addedPoint);
      }
284
    }
285 286 287 288 289
  if (this->PointsFunction == ColorPointsFunction ||
      this->PointsFunction == ColorAndOpacityPointsFunction)
    {
    addedPoint = this->Superclass::AddPoint(newPos);
    }
290
  this->EndChanges();
291
  return addedPoint;
292 293 294 295 296
}

//-----------------------------------------------------------------------------
vtkIdType vtkCompositeControlPointsItem::RemovePoint(double* currentPoint)
{
297
  vtkIdType removedPoint = -1;
298 299 300 301 302
  if (!this->IsPointRemovable(this->GetControlPointId(currentPoint)))
    {
    return removedPoint;
    }

303
  this->StartChanges();
304 305
  if (this->PointsFunction == ColorPointsFunction ||
      this->PointsFunction == ColorAndOpacityPointsFunction)
306
    {
307
    removedPoint = this->Superclass::RemovePoint(currentPoint);
308
    }
309 310 311 312 313 314
  if (this->OpacityFunction &&
      (this->PointsFunction == OpacityPointsFunction ||
       this->PointsFunction == ColorAndOpacityPointsFunction))
    {
    removedPoint = this->OpacityFunction->RemovePoint(currentPoint[0]);
    }
315
  this->EndChanges();
316
  return removedPoint;
317 318 319
}

//-----------------------------------------------------------------------------
320
void vtkCompositeControlPointsItem::MergeTransferFunctions()
321 322 323 324 325 326 327 328 329 330 331 332 333 334
{
  if (!this->ColorTransferFunction || !this->OpacityFunction)
    {
    return;
    }
  // 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)
    {
    double piecewisePoint[4];
    this->OpacityFunction->GetNodeValue(i, piecewisePoint);
    double rgb[3];
    this->ColorTransferFunction->GetColor(piecewisePoint[0], rgb);
Bill Lorensen's avatar
Bill Lorensen committed
335
    // note that we might lose the midpoint/sharpness of the point if any
336 337 338 339 340 341 342 343 344 345
    this->ColorTransferFunction->RemovePoint(piecewisePoint[0]);
    this->ColorTransferFunction->AddRGBPoint(piecewisePoint[0], rgb[0], rgb[1], rgb[2], piecewisePoint[2], piecewisePoint[3]);
    }
  // Copy ColorTransferFunction points into the OpacityFunction
  const int colorFunctionCount = this->ColorTransferFunction->GetSize();
  for (int i = 0; i < colorFunctionCount; ++i)
    {
    double xrgbms[6];
    this->ColorTransferFunction->GetNodeValue(i, xrgbms);
    double value = this->OpacityFunction->GetValue(xrgbms[0]);
Bill Lorensen's avatar
Bill Lorensen committed
346
    // note that we might lose the midpoint/sharpness of the point if any
347 348 349 350
    this->OpacityFunction->RemovePoint(xrgbms[0]);
    this->OpacityFunction->AddPoint(xrgbms[0], value, xrgbms[4], xrgbms[5]);
    }
}
351

352 353 354
//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::SilentMergeTransferFunctions()
{
355
  this->StartChanges();
356
  this->MergeTransferFunctions();
357
  this->EndChanges();
358
}
359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432

//-----------------------------------------------------------------------------
bool vtkCompositeControlPointsItem::MouseButtonPressEvent(const vtkContextMouseEvent &mouse)
{
  bool result=false;
  if(this->OpacityPointHandle && this->OpacityPointHandle->GetVisible())
    {
    result = this->OpacityPointHandle->MouseButtonPressEvent(mouse);
    }
  if(!result)
    {
    result = this->Superclass::MouseButtonPressEvent(mouse);
    if(result && this->OpacityPointHandle &&
     this->OpacityPointHandle->GetVisible() &&
     this->OpacityPointHandle->GetCurrentPointIndex() !=
     this->GetCurrentPoint())
      {
      this->OpacityPointHandle->SetVisible(false);
      }
    }
  return result;
}

//-----------------------------------------------------------------------------
bool vtkCompositeControlPointsItem::MouseDoubleClickEvent(const vtkContextMouseEvent &mouse)
{
   bool superRes = this->Superclass::MouseDoubleClickEvent(mouse);
   if(superRes)
     {
     vtkIdType curIdx = this->GetCurrentPoint();
     this->EditPointCurve(curIdx);
     }
   return superRes;
}

//-----------------------------------------------------------------------------
bool vtkCompositeControlPointsItem::MouseMoveEvent(const vtkContextMouseEvent &mouse)
{
  bool result=false;
  if(this->OpacityPointHandle && this->OpacityPointHandle->GetVisible())
    {
    result = this->OpacityPointHandle->MouseMoveEvent(mouse);
    }
  if(!result)
    {
    result = this->Superclass::MouseMoveEvent(mouse);
    }
  return result;
}

//-----------------------------------------------------------------------------
void vtkCompositeControlPointsItem::EditPointCurve(vtkIdType index)
{
  if(index<0 || index>=this->GetNumberOfPoints())
    {
    return;
    }
  if(this->GetUseOpacityPointHandles())
    {
    if(!this->OpacityPointHandle)
      {
      this->OpacityPointHandle = vtkPiecewisePointHandleItem::New();
      this->AddItem(this->OpacityPointHandle);
      this->OpacityPointHandle->SetPiecewiseFunction(
        this->GetOpacityFunction());
      }
    else
      {
      this->OpacityPointHandle->SetVisible(
        !this->OpacityPointHandle->GetVisible());
      this->GetScene()->SetDirty(true);
      }
    }
}