/*========================================================================= Program: Visualization Toolkit Module: vtkCompositePolyDataMapper.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 "vtkCompositePolyDataMapper.h" #include "vtkActor.h" #include "vtkCompositeDataIterator.h" #include "vtkCompositeDataPipeline.h" #include "vtkCompositeDataSet.h" #include "vtkExecutive.h" #include "vtkGarbageCollector.h" #include "vtkInformation.h" #include "vtkMapper.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include vtkStandardNewMacro(vtkCompositePolyDataMapper); class vtkCompositePolyDataMapperInternals { public: std::vector Mappers; }; vtkCompositePolyDataMapper::vtkCompositePolyDataMapper() { this->Internal = new vtkCompositePolyDataMapperInternals; } vtkCompositePolyDataMapper::~vtkCompositePolyDataMapper() { for (unsigned int i = 0; i < this->Internal->Mappers.size(); i++) { this->Internal->Mappers[i]->UnRegister(this); } this->Internal->Mappers.clear(); delete this->Internal; } // Specify the type of data this mapper can handle. If we are // working with a regular (not hierarchical) pipeline, then we // need vtkPolyData. For composite data pipelines, then // vtkCompositeDataSet is required, and we'll check when // building our structure whether all the part of the composite // data set are polydata. int vtkCompositePolyDataMapper::FillInputPortInformation(int vtkNotUsed(port), vtkInformation* info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataObject"); return 1; } // When the structure is out-of-date, recreate it by // creating a mapper for each input data. void vtkCompositePolyDataMapper::BuildPolyDataMapper() { int warnOnce = 0; // Delete pdmappers if they already exist. for (unsigned int i = 0; i < this->Internal->Mappers.size(); i++) { this->Internal->Mappers[i]->UnRegister(this); } this->Internal->Mappers.clear(); // Get the composite dataset from the input vtkInformation* inInfo = this->GetExecutive()->GetInputInformation(0, 0); vtkCompositeDataSet* input = vtkCompositeDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); // If it isn't hierarchical, maybe it is just a plain vtkPolyData if (!input) { vtkPolyData* pd = vtkPolyData::SafeDownCast(this->GetExecutive()->GetInputData(0, 0)); if (pd) { // Make a copy of the data to break the pipeline here vtkPolyData* newpd = vtkPolyData::New(); newpd->ShallowCopy(pd); vtkPolyDataMapper* pdmapper = this->MakeAMapper(); pdmapper->Register(this); pdmapper->SetInputData(newpd); this->Internal->Mappers.push_back(pdmapper); newpd->Delete(); pdmapper->Delete(); } else { vtkDataObject* tmpInp = this->GetExecutive()->GetInputData(0, 0); vtkErrorMacro("This mapper cannot handle input of type: " << (tmpInp ? tmpInp->GetClassName() : "(none)")); } } else { // for each data set build a vtkPolyDataMapper vtkCompositeDataIterator* iter = input->NewIterator(); iter->GoToFirstItem(); while (!iter->IsDoneWithTraversal()) { vtkPolyData* pd = vtkPolyData::SafeDownCast(iter->GetCurrentDataObject()); if (pd) { // Make a copy of the data to break the pipeline here vtkPolyData* newpd = vtkPolyData::New(); newpd->ShallowCopy(pd); vtkPolyDataMapper* pdmapper = this->MakeAMapper(); pdmapper->Register(this); pdmapper->SetInputData(newpd); this->Internal->Mappers.push_back(pdmapper); newpd->Delete(); pdmapper->Delete(); } // This is not polydata - warn the user that there are non-polydata // parts to this data set which will not be rendered by this mapper else { if (!warnOnce) { vtkErrorMacro("All data in the hierarchical dataset must be polydata."); warnOnce = 1; } } iter->GoToNextItem(); } iter->Delete(); } this->InternalMappersBuildTime.Modified(); } void vtkCompositePolyDataMapper::Render(vtkRenderer* ren, vtkActor* a) { // If the PolyDataMappers are not up-to-date then rebuild them vtkCompositeDataPipeline* executive = vtkCompositeDataPipeline::SafeDownCast(this->GetExecutive()); if (executive->GetPipelineMTime() > this->InternalMappersBuildTime.GetMTime()) { this->BuildPolyDataMapper(); } this->TimeToDraw = 0; // Call Render() on each of the PolyDataMappers for (unsigned int i = 0; i < this->Internal->Mappers.size(); i++) { // skip if we have a mismatch in opaque and translucent if (a->IsRenderingTranslucentPolygonalGeometry() == this->Internal->Mappers[i]->HasOpaqueGeometry()) { continue; } if (this->ClippingPlanes != this->Internal->Mappers[i]->GetClippingPlanes()) { this->Internal->Mappers[i]->SetClippingPlanes(this->ClippingPlanes); } this->Internal->Mappers[i]->SetLookupTable(this->GetLookupTable()); this->Internal->Mappers[i]->SetScalarVisibility(this->GetScalarVisibility()); this->Internal->Mappers[i]->SetUseLookupTableScalarRange(this->GetUseLookupTableScalarRange()); this->Internal->Mappers[i]->SetScalarRange(this->GetScalarRange()); this->Internal->Mappers[i]->SetColorMode(this->GetColorMode()); this->Internal->Mappers[i]->SetInterpolateScalarsBeforeMapping( this->GetInterpolateScalarsBeforeMapping()); this->Internal->Mappers[i]->SetScalarMode(this->GetScalarMode()); if (this->ScalarMode == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA || this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA) { if (this->ArrayAccessMode == VTK_GET_ARRAY_BY_ID) { this->Internal->Mappers[i]->ColorByArrayComponent(this->ArrayId, ArrayComponent); } else { this->Internal->Mappers[i]->ColorByArrayComponent(this->ArrayName, ArrayComponent); } } this->Internal->Mappers[i]->Render(ren, a); this->TimeToDraw += this->Internal->Mappers[i]->GetTimeToDraw(); } } vtkExecutive* vtkCompositePolyDataMapper::CreateDefaultExecutive() { return vtkCompositeDataPipeline::New(); } // Looks at each DataSet and finds the union of all the bounds void vtkCompositePolyDataMapper::ComputeBounds() { vtkMath::UninitializeBounds(this->Bounds); vtkInformation* inInfo = this->GetExecutive()->GetInputInformation(0, 0); vtkCompositeDataSet* input = vtkCompositeDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); // If we don't have hierarchical data, test to see if we have // plain old polydata. In this case, the bounds are simply // the bounds of the input polydata. if (!input) { vtkPolyData* pd = vtkPolyData::SafeDownCast(this->GetExecutive()->GetInputData(0, 0)); if (pd) { pd->GetCellsBounds(this->Bounds); } this->BoundsMTime.Modified(); return; } // We do have hierarchical data - so we need to loop over // it and get the total bounds. vtkCompositeDataIterator* iter = input->NewIterator(); iter->GoToFirstItem(); double bounds[6]; int i; while (!iter->IsDoneWithTraversal()) { vtkPolyData* pd = vtkPolyData::SafeDownCast(iter->GetCurrentDataObject()); if (pd) { // If this isn't the first time through, expand bounds // we've compute so far based on the bounds of this // block if (vtkMath::AreBoundsInitialized(this->Bounds)) { pd->GetCellsBounds(bounds); if (vtkMath::AreBoundsInitialized(bounds)) { for (i = 0; i < 3; i++) { this->Bounds[i * 2] = (bounds[i * 2] < this->Bounds[i * 2]) ? (bounds[i * 2]) : (this->Bounds[i * 2]); this->Bounds[i * 2 + 1] = (bounds[i * 2 + 1] > this->Bounds[i * 2 + 1]) ? (bounds[i * 2 + 1]) : (this->Bounds[i * 2 + 1]); } } } // If this is our first time through, just get the bounds // of the data as the initial bounds else { pd->GetCellsBounds(this->Bounds); } } iter->GoToNextItem(); } iter->Delete(); this->BoundsMTime.Modified(); } double* vtkCompositePolyDataMapper::GetBounds() { if (!this->GetExecutive()->GetInputData(0, 0)) { vtkMath::UninitializeBounds(this->Bounds); return this->Bounds; } else { this->Update(); // only compute bounds when the input data has changed vtkCompositeDataPipeline* executive = vtkCompositeDataPipeline::SafeDownCast(this->GetExecutive()); if (executive->GetPipelineMTime() > this->BoundsMTime.GetMTime()) { this->ComputeBounds(); } return this->Bounds; } } void vtkCompositePolyDataMapper::ReleaseGraphicsResources(vtkWindow* win) { for (unsigned int i = 0; i < this->Internal->Mappers.size(); i++) { this->Internal->Mappers[i]->ReleaseGraphicsResources(win); } } void vtkCompositePolyDataMapper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } vtkPolyDataMapper* vtkCompositePolyDataMapper::MakeAMapper() { vtkPolyDataMapper* m = vtkPolyDataMapper::New(); // Copy our vtkMapper properties to the delegate m->vtkMapper::ShallowCopy(this); return m; } //------------------------------------------------------------------------------ // look at children bool vtkCompositePolyDataMapper::HasOpaqueGeometry() { // If the PolyDataMappers are not up-to-date then rebuild them vtkCompositeDataPipeline* executive = vtkCompositeDataPipeline::SafeDownCast(this->GetExecutive()); if (executive->GetPipelineMTime() > this->InternalMappersBuildTime.GetMTime()) { this->BuildPolyDataMapper(); } bool hasOpaque = false; for (unsigned int i = 0; !hasOpaque && i < this->Internal->Mappers.size(); i++) { hasOpaque = hasOpaque || this->Internal->Mappers[i]->HasOpaqueGeometry(); } return hasOpaque; } //------------------------------------------------------------------------------ // look at children bool vtkCompositePolyDataMapper::HasTranslucentPolygonalGeometry() { // If the PolyDataMappers are not up-to-date then rebuild them vtkCompositeDataPipeline* executive = vtkCompositeDataPipeline::SafeDownCast(this->GetExecutive()); if (executive->GetPipelineMTime() > this->InternalMappersBuildTime.GetMTime()) { this->BuildPolyDataMapper(); } bool hasTrans = false; for (unsigned int i = 0; !hasTrans && i < this->Internal->Mappers.size(); i++) { hasTrans = hasTrans || this->Internal->Mappers[i]->HasTranslucentPolygonalGeometry(); } return hasTrans; }