/*========================================================================= Program: Visualization Toolkit Module: vtkPlotFunctionalBag.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 "vtkPlotFunctionalBag.h" #include "vtkAbstractArray.h" #include "vtkAxis.h" #include "vtkBrush.h" #include "vtkContext2D.h" #include "vtkContextMapper2D.h" #include "vtkDoubleArray.h" #include "vtkIdTypeArray.h" #include "vtkLookupTable.h" #include "vtkObjectFactory.h" #include "vtkPen.h" #include "vtkPlotLine.h" #include "vtkPoints2D.h" #include "vtkRect.h" #include "vtkScalarsToColors.h" #include "vtkTable.h" //------------------------------------------------------------------------------ vtkStandardNewMacro(vtkPlotFunctionalBag); //------------------------------------------------------------------------------ vtkPlotFunctionalBag::vtkPlotFunctionalBag() { this->LookupTable = nullptr; this->TooltipDefaultLabelFormat = "%l (%x, %y)"; this->LogX = false; this->LogY = false; } //------------------------------------------------------------------------------ vtkPlotFunctionalBag::~vtkPlotFunctionalBag() { if (this->LookupTable) { this->LookupTable->UnRegister(this); } } //------------------------------------------------------------------------------ bool vtkPlotFunctionalBag::IsBag() { this->Update(); return (this->BagPoints->GetNumberOfPoints() > 0); } //------------------------------------------------------------------------------ bool vtkPlotFunctionalBag::GetVisible() { return this->Superclass::GetVisible() || this->GetSelection() != nullptr; } bool vtkPlotFunctionalBag::CacheRequiresUpdate() { return this->Superclass::CacheRequiresUpdate() || (this->XAxis && this->LogX != this->XAxis->GetLogScaleActive()) || (this->YAxis && this->LogY != this->YAxis->GetLogScaleActive()) || (this->LookupTable && this->LookupTable->GetMTime() > this->BuildTime); } //------------------------------------------------------------------------------ bool vtkPlotFunctionalBag::UpdateCache() { if (!this->Superclass::UpdateCache()) { return false; } vtkTable* table = this->Data->GetInput(); if (!this->LookupTable) { this->CreateDefaultLookupTable(); this->LookupTable->SetRange(0, table->GetNumberOfColumns()); this->LookupTable->Build(); } this->BagPoints->Reset(); vtkDataArray* array[2] = { nullptr, nullptr }; if (!this->GetDataArrays(table, array)) { this->BuildTime.Modified(); return false; } if (array[1]->GetNumberOfComponents() == 1) { // The input array has one component, manage it as a line this->Line->SetInputData(table, array[0] ? array[0]->GetName() : "", array[1]->GetName()); this->Line->SetUseIndexForXSeries(this->UseIndexForXSeries); this->Line->SetMarkerStyle(vtkPlotPoints::NONE); this->Line->SetPen(this->Pen); this->Line->SetBrush(this->Brush); this->Line->Update(); } else if (array[1]->GetNumberOfComponents() == 2) { // The input array has 2 components, this must be a bag // with {miny,maxy} tuples vtkDoubleArray* darr = vtkArrayDownCast(array[1]); this->LogX = this->XAxis->GetLogScaleActive(); this->LogY = this->YAxis->GetLogScaleActive(); bool xAbs = this->XAxis->GetUnscaledMinimum() < 0.; bool yAbs = this->YAxis->GetUnscaledMinimum() < 0.; if (darr) { vtkIdType nbRows = array[1]->GetNumberOfTuples(); this->BagPoints->SetNumberOfPoints(2 * nbRows); for (vtkIdType i = 0; i < nbRows; i++) { double y[2]; darr->GetTuple(i, y); double x = (!this->UseIndexForXSeries && array[0]) ? array[0]->GetVariantValue(i).ToDouble() : static_cast(i); if (this->LogX) { x = xAbs ? log10(fabs(x)) : log10(x); } if (this->LogY) { y[0] = yAbs ? log10(fabs(y[0])) : log10(y[0]); y[1] = yAbs ? log10(fabs(y[1])) : log10(y[1]); } this->BagPoints->SetPoint(2 * i, x, y[0]); this->BagPoints->SetPoint(2 * i + 1, x, y[1]); } this->BagPoints->Modified(); } } this->BuildTime.Modified(); return true; } //------------------------------------------------------------------------------ bool vtkPlotFunctionalBag::GetDataArrays(vtkTable* table, vtkDataArray* array[2]) { if (!table) { return false; } // Get the x and y arrays (index 0 and 1 respectively) array[0] = this->UseIndexForXSeries ? nullptr : this->Data->GetInputArrayToProcess(0, table); array[1] = this->Data->GetInputArrayToProcess(1, table); if (!array[0] && !this->UseIndexForXSeries) { vtkErrorMacro(<< "No X column is set (index 0)."); return false; } else if (!array[1]) { vtkErrorMacro(<< "No Y column is set (index 1)."); return false; } else if (!this->UseIndexForXSeries && array[0]->GetNumberOfTuples() != array[1]->GetNumberOfTuples()) { vtkErrorMacro("The x and y columns must have the same number of elements. " << array[0]->GetNumberOfTuples() << ", " << array[1]->GetNumberOfTuples()); return false; } return true; } //------------------------------------------------------------------------------ bool vtkPlotFunctionalBag::Paint(vtkContext2D* painter) { // This is where everything should be drawn, or dispatched to other methods. vtkDebugMacro(<< "Paint event called in vtkPlotFunctionalBag."); if (!this->GetVisible()) { return false; } vtkPen* pen = this->GetSelection() ? this->SelectionPen : this->Pen; if (this->IsBag()) { double pwidth = pen->GetWidth(); pen->SetWidth(0.); painter->ApplyPen(pen); unsigned char pcolor[4]; pen->GetColor(pcolor); this->Brush->SetColor(pcolor); painter->ApplyBrush(this->Brush); painter->DrawQuadStrip(this->BagPoints); pen->SetWidth(pwidth); } else { this->Line->SetPen(pen); this->Line->Paint(painter); } return true; } //------------------------------------------------------------------------------ bool vtkPlotFunctionalBag::PaintLegend(vtkContext2D* painter, const vtkRectf& rect, int index) { if (this->BagPoints->GetNumberOfPoints() > 0) { vtkNew blackPen; blackPen->SetWidth(1.0); blackPen->SetColor(0, 0, 0, 255); painter->ApplyPen(blackPen); painter->ApplyBrush(this->Brush); painter->DrawRect(rect[0], rect[1], rect[2], rect[3]); } else { this->Line->PaintLegend(painter, rect, index); } return true; } //------------------------------------------------------------------------------ vtkIdType vtkPlotFunctionalBag::GetNearestPoint( const vtkVector2f& point, const vtkVector2f& tol, vtkVector2f* location, vtkIdType* segmentId) { if (this->BagPoints->GetNumberOfPoints() == 0) { return this->Line->GetNearestPoint(point, tol, location, segmentId); } return -1; } //------------------------------------------------------------------------------ bool vtkPlotFunctionalBag::SelectPoints(const vtkVector2f& min, const vtkVector2f& max) { if (!this->IsBag()) { return this->Line->SelectPoints(min, max); } return false; } //------------------------------------------------------------------------------ bool vtkPlotFunctionalBag::SelectPointsInPolygon(const vtkContextPolygon& polygon) { if (!this->IsBag()) { return this->Line->SelectPointsInPolygon(polygon); } return false; } //------------------------------------------------------------------------------ void vtkPlotFunctionalBag::GetBounds(double bounds[4]) { if (this->BagPoints->GetNumberOfPoints() > 0) { this->BagPoints->GetBounds(bounds); if (this->LogX) { bounds[0] = log10(bounds[0]); bounds[1] = log10(bounds[1]); } if (this->LogY) { bounds[2] = log10(bounds[2]); bounds[3] = log10(bounds[3]); } } else { this->Line->GetBounds(bounds); } vtkDebugMacro(<< "Bounds: " << bounds[0] << "\t" << bounds[1] << "\t" << bounds[2] << "\t" << bounds[3]); } //------------------------------------------------------------------------------ void vtkPlotFunctionalBag::GetUnscaledInputBounds(double bounds[4]) { if (this->BagPoints->GetNumberOfPoints() > 0) { this->BagPoints->GetBounds(bounds); } else { this->Line->GetUnscaledInputBounds(bounds); } vtkDebugMacro(<< "Bounds: " << bounds[0] << "\t" << bounds[1] << "\t" << bounds[2] << "\t" << bounds[3]); } //------------------------------------------------------------------------------ void vtkPlotFunctionalBag::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //------------------------------------------------------------------------------ void vtkPlotFunctionalBag::SetLookupTable(vtkScalarsToColors* lut) { if (this->LookupTable != lut) { if (this->LookupTable) { this->LookupTable->UnRegister(this); } this->LookupTable = lut; if (lut) { lut->Register(this); } this->Modified(); } } //------------------------------------------------------------------------------ vtkScalarsToColors* vtkPlotFunctionalBag::GetLookupTable() { if (this->LookupTable == nullptr) { this->CreateDefaultLookupTable(); } return this->LookupTable; } //------------------------------------------------------------------------------ void vtkPlotFunctionalBag::CreateDefaultLookupTable() { if (this->LookupTable) { this->LookupTable->UnRegister(this); } this->LookupTable = vtkLookupTable::New(); // Consistent Register/UnRegisters. this->LookupTable->Register(this); this->LookupTable->Delete(); }