You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
479 lines
14 KiB
479 lines
14 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkExtentSplitter.cxx,v $
|
|
|
|
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 "vtkExtentSplitter.h"
|
|
|
|
#include "vtkObjectFactory.h"
|
|
|
|
#include <vtkstd/map>
|
|
#include <vtkstd/queue>
|
|
#include <vtkstd/vector>
|
|
|
|
vtkCxxRevisionMacro(vtkExtentSplitter, "$Revision: 1.4 $");
|
|
vtkStandardNewMacro(vtkExtentSplitter);
|
|
|
|
//----------------------------------------------------------------------------
|
|
struct vtkExtentSplitterExtent
|
|
{
|
|
int extent[6];
|
|
};
|
|
|
|
struct vtkExtentSplitterSource
|
|
{
|
|
int extent[6];
|
|
int priority;
|
|
};
|
|
|
|
struct vtkExtentSplitterSubExtent
|
|
{
|
|
int extent[6];
|
|
int source;
|
|
};
|
|
|
|
class vtkExtentSplitterInternals
|
|
{
|
|
public:
|
|
typedef vtkstd::queue<vtkExtentSplitterExtent> QueueType;
|
|
typedef vtkstd::map<int, vtkExtentSplitterSource> SourcesType;
|
|
typedef vtkstd::vector<vtkExtentSplitterSubExtent> SubExtentsType;
|
|
SourcesType Sources;
|
|
QueueType Queue;
|
|
SubExtentsType SubExtents;
|
|
};
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkExtentSplitter::vtkExtentSplitter()
|
|
{
|
|
this->Internal = new vtkExtentSplitterInternals;
|
|
this->PointMode = 0;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkExtentSplitter::~vtkExtentSplitter()
|
|
{
|
|
delete this->Internal;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkExtentSplitter::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
vtkIndent nextIndent = indent.GetNextIndent();
|
|
os << indent << "PointMode: " << this->PointMode << "\n";
|
|
if(this->Internal->Sources.empty())
|
|
{
|
|
os << indent << "Extent Sources: (none)\n";
|
|
}
|
|
else
|
|
{
|
|
os << indent << "Extent Sources: (format = \"id priority: extent\")\n";
|
|
for(vtkExtentSplitterInternals::SourcesType::const_iterator src =
|
|
this->Internal->Sources.begin();
|
|
src != this->Internal->Sources.end(); ++src)
|
|
{
|
|
const int* extent = src->second.extent;
|
|
os << nextIndent << src->first
|
|
<< " " << src->second.priority << ": "
|
|
<< extent[0] << " " << extent[1] << " "
|
|
<< extent[2] << " " << extent[3] << " "
|
|
<< extent[4] << " " << extent[5] << "\n";
|
|
}
|
|
}
|
|
os << indent << "Number of Extents in Queue: " <<
|
|
(int)this->Internal->Queue.size() << "\n";
|
|
if(this->Internal->SubExtents.empty())
|
|
{
|
|
os << indent << "SubExtents: (none)\n";
|
|
}
|
|
else
|
|
{
|
|
os << indent << "SubExtents: (format = \"id: extent\")\n";
|
|
for(vtkExtentSplitterInternals::SubExtentsType::const_iterator i =
|
|
this->Internal->SubExtents.begin();
|
|
i != this->Internal->SubExtents.end(); ++i)
|
|
{
|
|
const int* extent = i->extent;
|
|
os << nextIndent << i->source << ": "
|
|
<< extent[0] << " " << extent[1] << " "
|
|
<< extent[2] << " " << extent[3] << " "
|
|
<< extent[4] << " " << extent[5] << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkExtentSplitter::AddExtentSource(int id, int priority, int x0, int x1,
|
|
int y0, int y1, int z0, int z1)
|
|
{
|
|
// Add the source.
|
|
vtkExtentSplitterSource& source = this->Internal->Sources[id];
|
|
source.extent[0] = x0;
|
|
source.extent[1] = x1;
|
|
source.extent[2] = y0;
|
|
source.extent[3] = y1;
|
|
source.extent[4] = z0;
|
|
source.extent[5] = z1;
|
|
source.priority = priority;
|
|
|
|
// Previously calculated sub-extents are now invalid.
|
|
this->Internal->SubExtents.clear();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkExtentSplitter::AddExtentSource(int id, int priority, int* extent)
|
|
{
|
|
this->AddExtentSource(id, priority, extent[0], extent[1], extent[2],
|
|
extent[3], extent[4], extent[5]);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkExtentSplitter::RemoveExtentSource(int id)
|
|
{
|
|
// Remove the source.
|
|
this->Internal->Sources.erase(id);
|
|
|
|
// Previously calculated sub-extents are now invalid.
|
|
this->Internal->SubExtents.clear();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkExtentSplitter::RemoveAllExtentSources()
|
|
{
|
|
// Clear the set of sources.
|
|
this->Internal->Sources.clear();
|
|
|
|
// Previously calculated sub-extents are now invalid.
|
|
this->Internal->SubExtents.clear();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkExtentSplitter::AddExtent(int x0, int x1, int y0, int y1,
|
|
int z0, int z1)
|
|
{
|
|
// Queue the extent.
|
|
vtkExtentSplitterExtent e;
|
|
e.extent[0] = x0;
|
|
e.extent[1] = x1;
|
|
e.extent[2] = y0;
|
|
e.extent[3] = y1;
|
|
e.extent[4] = z0;
|
|
e.extent[5] = z1;
|
|
this->Internal->Queue.push(e);
|
|
|
|
// Previously calculated sub-extents are now invalid.
|
|
this->Internal->SubExtents.clear();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkExtentSplitter::AddExtent(int* extent)
|
|
{
|
|
this->AddExtent(extent[0], extent[1], extent[2],
|
|
extent[3], extent[4], extent[5]);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkExtentSplitter::GetNumberOfSubExtents()
|
|
{
|
|
return static_cast<int>(this->Internal->SubExtents.size());
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int* vtkExtentSplitter::GetSubExtent(int index)
|
|
{
|
|
if(index < 0 || index >= this->GetNumberOfSubExtents())
|
|
{
|
|
static int dummy[6] = {0, -1, 0, -1, 0, -1};
|
|
vtkErrorMacro("SubExtent index " << index << " is out of range [0,"
|
|
<< this->GetNumberOfSubExtents()-1 << "]");
|
|
return dummy;
|
|
}
|
|
return this->Internal->SubExtents[index].extent;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkExtentSplitter::GetSubExtent(int index, int* extent)
|
|
{
|
|
if(index < 0 || index >= this->GetNumberOfSubExtents())
|
|
{
|
|
vtkErrorMacro("SubExtent index " << index << " is out of range [0,"
|
|
<< this->GetNumberOfSubExtents()-1 << "]");
|
|
extent[0] = 0;
|
|
extent[1] = -1;
|
|
extent[2] = 0;
|
|
extent[3] = -1;
|
|
extent[4] = 0;
|
|
extent[5] = -1;
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
int* e = this->Internal->SubExtents[index].extent;
|
|
for(i=0; i < 6; ++i)
|
|
{
|
|
extent[i] = e[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkExtentSplitter::GetSubExtentSource(int index)
|
|
{
|
|
if(index < 0 || index >= this->GetNumberOfSubExtents())
|
|
{
|
|
vtkErrorMacro("SubExtent index " << index << " is out of range [0,"
|
|
<< this->GetNumberOfSubExtents()-1 << "]");
|
|
return -1;
|
|
}
|
|
return this->Internal->SubExtents[index].source;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkExtentSplitter::ComputeSubExtents()
|
|
{
|
|
// Assume success.
|
|
int result = 1;
|
|
|
|
vtkExtentSplitterInternals::SubExtentsType subExtents;
|
|
int bestPriority;
|
|
int dimensionality = 0;
|
|
|
|
while(!this->Internal->Queue.empty())
|
|
{
|
|
// Pop the next extent off the queue.
|
|
vtkExtentSplitterExtent e = this->Internal->Queue.front();
|
|
this->Internal->Queue.pop();
|
|
|
|
// In non-PointMode, intersections must have the same topological
|
|
// dimension as the original extent. This will prevent
|
|
// high-priority source extents from repeatedly producing
|
|
// single-point-wide intersections.
|
|
if(!this->PointMode)
|
|
{
|
|
dimensionality = (((e.extent[1]-e.extent[0] > 0)?1:0)+
|
|
((e.extent[3]-e.extent[2] > 0)?1:0)+
|
|
((e.extent[5]-e.extent[4] > 0)?1:0));
|
|
}
|
|
|
|
// Intersect the extent with each extent source.
|
|
subExtents.clear();
|
|
bestPriority = -1;
|
|
vtkExtentSplitterSubExtent se;
|
|
for(vtkExtentSplitterInternals::SourcesType::const_iterator src =
|
|
this->Internal->Sources.begin();
|
|
src != this->Internal->Sources.end(); ++src)
|
|
{
|
|
se.source = src->first;
|
|
if(this->IntersectExtents(e.extent, src->second.extent, se.extent) &&
|
|
(this->PointMode ||
|
|
(dimensionality == (((se.extent[1]-se.extent[0] > 0)?1:0)+
|
|
((se.extent[3]-se.extent[2] > 0)?1:0)+
|
|
((se.extent[5]-se.extent[4] > 0)?1:0)))))
|
|
{
|
|
// Non-zero intersection volume. Add the extent as a
|
|
// candidate for best extent.
|
|
if(src->second.priority > bestPriority)
|
|
{
|
|
// New highest priority. Clear previous intersections with
|
|
// lower priority.
|
|
subExtents.clear();
|
|
subExtents.push_back(se);
|
|
bestPriority = src->second.priority;
|
|
}
|
|
else if(src->second.priority == bestPriority)
|
|
{
|
|
// Matching priority. Add this intersection to the list.
|
|
subExtents.push_back(se);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check whether any extent sources intersected the extent.
|
|
if(subExtents.empty())
|
|
{
|
|
// No extent source intersected the extent. Add the extent as
|
|
// an error.
|
|
int i;
|
|
result = 0;
|
|
se.source = -1;
|
|
for(i=0; i < 6; ++i)
|
|
{
|
|
se.extent[i] = e.extent[i];
|
|
}
|
|
this->Internal->SubExtents.push_back(se);
|
|
}
|
|
else
|
|
{
|
|
// Choose the extent intersection with the largest volume.
|
|
int bestVolume = 0;
|
|
int bestIndex = 0;
|
|
int i;
|
|
for(i=0; i < static_cast<int>(subExtents.size()); ++i)
|
|
{
|
|
int* extent = subExtents[i].extent;
|
|
int volume = ((extent[1]-extent[0]+1)*
|
|
(extent[3]-extent[2]+1)*
|
|
(extent[5]-extent[4]+1));
|
|
if(volume > bestVolume)
|
|
{
|
|
bestVolume = volume;
|
|
bestIndex = i;
|
|
}
|
|
}
|
|
|
|
// Add this extent source with its sub-extent.
|
|
se.source = subExtents[bestIndex].source;
|
|
for(i=0; i < 6; ++i)
|
|
{
|
|
se.extent[i] = subExtents[bestIndex].extent[i];
|
|
}
|
|
this->Internal->SubExtents.push_back(se);
|
|
|
|
// Subtract the sub-extent from the extent and split the rest of
|
|
// the volume into more sub-extents.
|
|
this->SplitExtent(e.extent, se.extent);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkExtentSplitter::SplitExtent(int* extent, int* subextent)
|
|
{
|
|
// Subtract the volume described by subextent from that described by
|
|
// extent. Split the remaining region into rectangular solids and
|
|
// queue them as additional extents. We may assume that subextent
|
|
// is completely contained by extent.
|
|
vtkExtentSplitterExtent e;
|
|
|
|
// In PointMode, there are no cell data, so we can skip over cells.
|
|
int pointMode = this->PointMode?1:0;
|
|
|
|
// Split with xy-planes.
|
|
if(extent[4] < subextent[4])
|
|
{
|
|
e.extent[0] = extent[0];
|
|
e.extent[1] = extent[1];
|
|
e.extent[2] = extent[2];
|
|
e.extent[3] = extent[3];
|
|
e.extent[4] = extent[4];
|
|
e.extent[5] = subextent[4]-pointMode;
|
|
this->Internal->Queue.push(e);
|
|
|
|
extent[4] = subextent[4];
|
|
}
|
|
if(extent[5] > subextent[5])
|
|
{
|
|
e.extent[0] = extent[0];
|
|
e.extent[1] = extent[1];
|
|
e.extent[2] = extent[2];
|
|
e.extent[3] = extent[3];
|
|
e.extent[4] = subextent[5]+pointMode;
|
|
e.extent[5] = extent[5];
|
|
this->Internal->Queue.push(e);
|
|
|
|
extent[5] = subextent[5];
|
|
}
|
|
|
|
// Split with xz-planes.
|
|
if(extent[2] < subextent[2])
|
|
{
|
|
e.extent[0] = extent[0];
|
|
e.extent[1] = extent[1];
|
|
e.extent[2] = extent[2];
|
|
e.extent[3] = subextent[2]-pointMode;
|
|
e.extent[4] = extent[4];
|
|
e.extent[5] = extent[5];
|
|
this->Internal->Queue.push(e);
|
|
|
|
extent[2] = subextent[2];
|
|
}
|
|
if(extent[3] > subextent[3])
|
|
{
|
|
e.extent[0] = extent[0];
|
|
e.extent[1] = extent[1];
|
|
e.extent[2] = subextent[3]+pointMode;
|
|
e.extent[3] = extent[3];
|
|
e.extent[4] = extent[4];
|
|
e.extent[5] = extent[5];
|
|
this->Internal->Queue.push(e);
|
|
|
|
extent[3] = subextent[3];
|
|
}
|
|
|
|
// Split with yz-planes.
|
|
if(extent[0] < subextent[0])
|
|
{
|
|
e.extent[0] = extent[0];
|
|
e.extent[1] = subextent[0]-pointMode;
|
|
e.extent[2] = extent[2];
|
|
e.extent[3] = extent[3];
|
|
e.extent[4] = extent[4];
|
|
e.extent[5] = extent[5];
|
|
this->Internal->Queue.push(e);
|
|
|
|
extent[0] = subextent[0];
|
|
}
|
|
if(extent[1] > subextent[1])
|
|
{
|
|
e.extent[0] = subextent[1]+pointMode;
|
|
e.extent[1] = extent[1];
|
|
e.extent[2] = extent[2];
|
|
e.extent[3] = extent[3];
|
|
e.extent[4] = extent[4];
|
|
e.extent[5] = extent[5];
|
|
this->Internal->Queue.push(e);
|
|
|
|
// Leave this line out because the value will not be used:
|
|
//extent[1] = subextent[1];
|
|
}
|
|
|
|
// At this point, we should have extent[i] == subextent[i] for 0 <= i < 6.
|
|
// No more volume remains.
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkExtentSplitter::IntersectExtents(const int* extent1, const int* extent2,
|
|
int* result)
|
|
{
|
|
if((extent1[0] > extent2[1]) || (extent1[2] > extent2[3]) ||
|
|
(extent1[4] > extent2[5]) || (extent1[1] < extent2[0]) ||
|
|
(extent1[3] < extent2[2]) || (extent1[5] < extent2[4]))
|
|
{
|
|
// No intersection of extents.
|
|
return 0;
|
|
}
|
|
|
|
// Get the intersection of the extents.
|
|
result[0] = this->Max(extent1[0], extent2[0]);
|
|
result[1] = this->Min(extent1[1], extent2[1]);
|
|
result[2] = this->Max(extent1[2], extent2[2]);
|
|
result[3] = this->Min(extent1[3], extent2[3]);
|
|
result[4] = this->Max(extent1[4], extent2[4]);
|
|
result[5] = this->Min(extent1[5], extent2[5]);
|
|
|
|
return 1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkExtentSplitter::Min(int a, int b)
|
|
{
|
|
return (a < b)? a : b;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkExtentSplitter::Max(int a, int b)
|
|
{
|
|
return (a > b)? a : b;
|
|
}
|
|
|