【简介】
该类是一个滤波器,主要的作用就是将多个多边形数据集扩展为单个的多边形数据集(应该说是多面体更加合适)。所有的几何信息都会被提取,但是点、单元属性(标量、向量、法线)的提取和扩展需要每个数据集有这个点或者单元属性,例如 如果一个数据集有点标量信息(如权重)而另一个数据集没有这个点的标量信息,那个这个点的标量信息不会被扩展。
【类继承】
【示例】
#include <vtkVersion.h>
#include <vtkSmartPointer.h>
#include <vtkPolyData.h>
#include <vtkSphereSource.h>
#include <vtkConeSource.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkCleanPolyData.h>
#include <vtkAppendPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
int main(int argc, char *argv[])
{
vtkSmartPointer<vtkPolyData> input1 =
vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkPolyData> input2 =
vtkSmartPointer<vtkPolyData>::New();
if(argc == 1) //command line arguments not specified
{
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->SetCenter(5,0,0);
sphereSource->Update();
input1->ShallowCopy(sphereSource->GetOutput());
vtkSmartPointer<vtkConeSource> coneSource =
vtkSmartPointer<vtkConeSource>::New();
coneSource->Update();
input2->ShallowCopy(coneSource->GetOutput());
}
else
{
if(argc != 3)
{
std::cout << "argc = " << argc << std::endl;
std::cout << "Required arguments: File1 File2" << std::endl;
return EXIT_FAILURE;
}
std::string inputFilename1 = argv[1];
std::string inputFilename2 = argv[2];
vtkSmartPointer<vtkXMLPolyDataReader> reader1 =
vtkSmartPointer<vtkXMLPolyDataReader>::New();
reader1->SetFileName(inputFilename1.c_str());
reader1->Update();
input1->ShallowCopy(reader1->GetOutput());
vtkSmartPointer<vtkXMLPolyDataReader> reader2 =
vtkSmartPointer<vtkXMLPolyDataReader>::New();
reader2->SetFileName(inputFilename2.c_str());
reader2->Update();
input2->ShallowCopy(reader2->GetOutput());
}
//Append the two meshes
vtkSmartPointer<vtkAppendPolyData> appendFilter =
vtkSmartPointer<vtkAppendPolyData>::New();
#if VTK_MAJOR_VERSION <= 5
appendFilter->AddInputConnection(input1->GetProducerPort());
appendFilter->AddInputConnection(input2->GetProducerPort());
#else
appendFilter->AddInputData(input1);
appendFilter->AddInputData(input2);
#endif
appendFilter->Update();
// Remove any duplicate points.
vtkSmartPointer<vtkCleanPolyData> cleanFilter =
vtkSmartPointer<vtkCleanPolyData>::New();
cleanFilter->SetInputConnection(appendFilter->GetOutputPort());
cleanFilter->Update();
//Create a mapper and actor
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(cleanFilter->GetOutputPort());
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
//Create a renderer, render window, and interactor
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetSize(900, 300);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
// Define viewport ranges
// (xmin, ymin, xmax, ymax)
double leftViewport[4] = {0.0, 0.0, 0.33, 1.0};
double centerViewport[4] = {0.33, 0.0, 0.66, 1.0};
double rightViewport[4] = {0.66, 0.0, 1.0, 1.0};
vtkSmartPointer<vtkPolyDataMapper> originalMapper1 = vtkSmartPointer<vtkPolyDataMapper>::New();
originalMapper1->SetInputData(input1);
vtkSmartPointer<vtkPolyDataMapper> originalMapper2 = vtkSmartPointer<vtkPolyDataMapper>::New();
originalMapper2->SetInputData(input2);
vtkSmartPointer<vtkActor> originalActor1 = vtkSmartPointer<vtkActor>::New();
originalActor1->SetMapper(originalMapper1);
//originalActor1->GetProperty()->SetColor(0.6, 0.6, 0.6);
vtkSmartPointer<vtkRenderer> originalRender1 = vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkActor> originalActor2 = vtkSmartPointer<vtkActor>::New();
originalActor2->SetMapper(originalMapper2);
vtkSmartPointer<vtkRenderer> originalRender2 = vtkSmartPointer<vtkRenderer>::New();
// Add the actors to the scene
renderer->AddActor(actor);
renderer->SetBackground(.3, .3, .3); // Background color dark red
renderWindow->AddRenderer(renderer);
renderer->SetViewport(rightViewport);
originalRender1->AddActor(originalActor1);
originalRender1->SetBackground(.6,.6,.6);
renderWindow->AddRenderer(originalRender1);
originalRender1->SetViewport(leftViewport);
originalRender2->AddActor(originalActor2);
originalRender2->SetBackground(.8,.8,.8);
renderWindow->AddRenderer(originalRender2);
originalRender2->SetViewport(centerViewport);
//Render and interact
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
结果图:
【源码分析】
看这个类的源代码没有多长一千行都不到
① RequestData() 为什么看这个函数,是因为vtkAppendPolyData这个类继承自vtkPolyDataAlgorithm,之前我也分析过这个类,这个类的子类在输入正确的数据之后调用Update(),默认的执行过程中入口就是这个函数,主要实现类的主要功能(可以这么讲)。
// This method is much too long, and has to be broken up!
// Append data sets into single polygonal data set.
int vtkAppendPolyData::RequestData(vtkInformation *vtkNotUsed(request),
vtkInformationVector **inputVector,
vtkInformationVector *outputVector)
{
// get the info object
// get the ouptut
vtkPolyData *output = vtkPolyData::GetData(outputVector, 0);
int numInputs = inputVector[0]->GetNumberOfInformationObjects();
if (numInputs == 1)
{
output->ShallowCopy(vtkPolyData::GetData(inputVector[0], 0));
return 1;
}
vtkPolyData** inputs = new vtkPolyData*[numInputs];
for (int idx = 0; idx < numInputs; ++idx)
{
inputs[idx] = vtkPolyData::GetData(inputVector[0], idx);
}
int retVal = this->ExecuteAppend(output, inputs, numInputs);
delete [] inputs;
return retVal;
}
其实代码很简单,首先获取输入输出,如果输入数据只有一个,那直接输出数据就是输入;多个输入数据时,调用
ExecuteAppend() ,需要注意的是 inputs 为一个二级指针,可以学习如何使用一个二级指针(C++ 学的没有很深,二级指针用的不熟,需要多学习)。
② ExecuteAppend() 这个函数的代码是有点长,好在代码整洁、干净,大部分都是数据的初始化等操作,对于数据的扩充调用AppendData().
该函数的功能就是将多个多边形数据连接成一个多边形数据。
//----------------------------------------------------------------------------
int vtkAppendPolyData::ExecuteAppend(vtkPolyData* output,
vtkPolyData* inputs[], int numInputs)
{
int idx;
vtkPolyData *ds;
vtkPoints *inPts;
vtkPoints *newPts;
vtkCellArray *inVerts, *newVerts;
vtkCellArray *inLines, *newLines;
vtkCellArray *inPolys, *newPolys;
vtkIdType sizePolys, numPolys;
vtkCellArray *inStrips, *newStrips;
vtkIdType numPts, numCells;
vtkPointData *inPD = NULL;
vtkCellData *inCD = NULL;
vtkPointData *outputPD = output->GetPointData();
vtkCellData *outputCD = output->GetCellData();
vtkDataArray *newPtScalars = NULL;
vtkDataArray *newPtVectors = NULL;
vtkDataArray *newPtNormals = NULL;
vtkDataArray *newPtTCoords = NULL;
vtkDataArray *newPtTensors = NULL;
int i;
vtkIdType *pts = 0;
vtkIdType *pPolys;
vtkIdType npts = 0;
vtkIdType ptId, cellId;
vtkDebugMacro(<<"Appending polydata");
// loop over all data sets, checking to see what point data is available.
numPts = 0;
numCells = 0;
sizePolys = numPolys = 0;
int countPD=0;
int countCD=0;
vtkIdType numVerts = 0, numLines = 0, numStrips = 0;
// These Field lists are very picky. Count the number of non empty inputs
// so we can initialize them properly.
for (idx = 0; idx < numInputs; ++idx)
{
ds = inputs[idx];
if (ds != NULL)
{
if ( ds->GetNumberOfPoints() > 0)
{
++countPD;
}
if (ds->GetNumberOfCells() > 0 )
{
++countCD;
} // for a data set that has cells
} // for a non NULL input
} // for each input
// These are used to determine which fields are available for appending
vtkDataSetAttributes::FieldList ptList(countPD);
vtkDataSetAttributes::FieldList cellList(countCD);
countPD = countCD = 0;
for (idx = 0; idx < numInputs; ++idx)
{
ds = inputs[idx];
if (ds != NULL)
{
// Skip points and cells if there are no points. Empty inputs may have no arrays.
if ( ds->GetNumberOfPoints() > 0)
{
numPts += ds->GetNumberOfPoints();
// Take intersection of available point data fields.
inPD = ds->GetPointData();
if ( countPD == 0 )
{
ptList.InitializeFieldList(inPD);
}
else
{
ptList.IntersectFieldList(inPD);
}
++countPD;
} // for a data set that has points
// Although we cannot have cells without points ... let's not nest.
if (ds->GetNumberOfCells() > 0 )
{
// keep track of the size of the poly cell array
if (ds->GetPolys())
{
sizePolys += ds->GetPolys()->GetNumberOfConnectivityEntries();
}
numCells += ds->GetNumberOfCells();
// Count the cells of each type.
// This is used to ensure that cell data is copied at the correct
// locations in the output.
numVerts += ds->GetNumberOfVerts();
numLines += ds->GetNumberOfLines();
numPolys += ds->GetNumberOfPolys();
numStrips += ds->GetNumberOfStrips();
inCD = ds->GetCellData();
if ( countCD == 0 )
{
cellList.InitializeFieldList(inCD);
}
else
{
cellList.IntersectFieldList(inCD);
}
++countCD;
} // for a data set that has cells
} // for a non NULL input
} // for each input
if ( numPts < 1 || numCells < 1 )
{
vtkDebugMacro(<<"No data to append!");
return 1;
}
this->UpdateProgress(0.10);
// Examine the points and check if they're the same type. If not,
// use highest (double probably), otherwise the type of the first
// array (float no doubt). Depends on defs in vtkSetGet.h - Warning.
int ttype, firstType=1, AllSame=1;
int pointtype = 0;
// Keep track of types for fast point append
for (idx = 0; idx < numInputs; ++idx)
{
ds = inputs[idx];
if (ds != NULL && ds->GetNumberOfPoints()>0)
{
if ( firstType )
{
firstType = 0;
pointtype = ds->GetPoints()->GetData()->GetDataType();
}
ttype = ds->GetPoints()->GetData()->GetDataType();
if ( ttype != pointtype )
{
AllSame = 0;
vtkDebugMacro(<<"Different point data types");
}
pointtype = pointtype > ttype ? pointtype : ttype;
}
}
// Allocate geometry/topology
newPts = vtkPoints::New();
// Set the desired precision for the points in the output.
if(this->OutputPointsPrecision == vtkAlgorithm::DEFAULT_PRECISION)
{
newPts->SetDataType(pointtype);
}
else if(this->OutputPointsPrecision == vtkAlgorithm::SINGLE_PRECISION)
{
newPts->SetDataType(VTK_FLOAT);
}
else if(this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION)
{
newPts->SetDataType(VTK_DOUBLE);
}
newPts->SetNumberOfPoints(numPts);
newVerts = vtkCellArray::New();
newVerts->Allocate(numCells*4);
newLines = vtkCellArray::New();
newLines->Allocate(numCells*4);
newStrips = vtkCellArray::New();
newStrips->Allocate(numCells*4);
newPolys = vtkCellArray::New();
pPolys = newPolys->WritePointer(numPolys, sizePolys);
if (!pPolys && sizePolys > 0)
{
vtkErrorMacro(<<"Memory allocation failed in append filter");
return 0;
}
// These are created manually for faster execution
// Uses the properties of the last input
vtkDataArray *inDA=0;
if ( ptList.IsAttributePresent(vtkDataSetAttributes::SCALARS) > -1 )
{
inDA=inPD->GetScalars();
outputPD->CopyScalarsOff();
newPtScalars = inDA->NewInstance();
newPtScalars->SetNumberOfComponents(inDA->GetNumberOfComponents());
newPtScalars->CopyComponentNames( inDA );
newPtScalars->SetName(inDA->GetName());
newPtScalars->SetNumberOfTuples(numPts);
if (inDA->HasInformation())
{
newPtScalars->CopyInformation(inDA->GetInformation(),/*deep=*/1);
}
}
if ( ptList.IsAttributePresent(vtkDataSetAttributes::VECTORS) > -1 )
{
inDA=inPD->GetVectors();
outputPD->CopyVectorsOff();
newPtVectors = inDA->NewInstance();
newPtVectors->SetNumberOfComponents(inDA->GetNumberOfComponents());
newPtVectors->CopyComponentNames( inDA );
newPtVectors->SetName(inDA->GetName());
newPtVectors->SetNumberOfTuples(numPts);
if (inDA->HasInformation())
{
newPtVectors->CopyInformation(inDA->GetInformation(),/*deep=*/1);
}
}
if ( ptList.IsAttributePresent(vtkDataSetAttributes::TENSORS) > -1 )
{
inDA=inPD->GetTensors();
outputPD->CopyTensorsOff();
newPtTensors = inDA->NewInstance();
newPtTensors->SetNumberOfComponents(inDA->GetNumberOfComponents());
newPtTensors->CopyComponentNames( inDA );
newPtTensors->SetName(inDA->GetName());
newPtTensors->SetNumberOfTuples(numPts);
if (inDA->HasInformation())
{
newPtTensors->CopyInformation(inDA->GetInformation(),/*deep=*/1);
}
}
if ( ptList.IsAttributePresent(vtkDataSetAttributes::NORMALS) > -1 )
{
inDA=inPD->GetNormals();
outputPD->CopyNormalsOff();
newPtNormals = inDA->NewInstance();
newPtNormals->SetNumberOfComponents(inDA->GetNumberOfComponents());
newPtNormals->CopyComponentNames( inDA );
newPtNormals->SetName(inDA->GetName());
newPtNormals->SetNumberOfTuples(numPts);
if (inDA->HasInformation())
{
newPtNormals->CopyInformation(inDA->GetInformation(),/*deep=*/1);
}
}
if ( ptList.IsAttributePresent(vtkDataSetAttributes::TCOORDS) > -1 )
{
inDA=inPD->GetTCoords();
outputPD->CopyTCoordsOff();
newPtTCoords = inDA->NewInstance();
newPtTCoords->SetNumberOfComponents(inDA->GetNumberOfComponents());
newPtTCoords->CopyComponentNames( inDA );
newPtTCoords->SetName(inDA->GetName());
newPtTCoords->SetNumberOfTuples(numPts);
if (inDA->HasInformation())
{
newPtTCoords->CopyInformation(inDA->GetInformation(),/*deep=*/1);
}
}
// Allocate the point and cell data
outputPD->CopyAllocate(ptList,numPts);
outputCD->CopyAllocate(cellList,numCells);
// loop over all input sets
vtkIdType ptOffset = 0;
vtkIdType vertOffset = 0;
vtkIdType linesOffset = 0;
vtkIdType polysOffset = 0;
vtkIdType stripsOffset = 0;
countPD = countCD = 0;
for (idx = 0; idx < numInputs; ++idx)
{
this->UpdateProgress(0.2 + 0.8*idx/numInputs);
ds = inputs[idx];
// this check is not necessary, but I'll put it in anyway
if (ds != NULL)
{
numPts = ds->GetNumberOfPoints();
numCells = ds->GetNumberOfCells();
if ( numPts <= 0 && numCells <= 0 )
{
continue; //no input, just skip
}
inPD = ds->GetPointData();
inCD = ds->GetCellData();
inPts = ds->GetPoints();
inVerts = ds->GetVerts();
inLines = ds->GetLines();
inPolys = ds->GetPolys();
inStrips = ds->GetStrips();
if (ds->GetNumberOfPoints() > 0)
{
// copy points directly
if (AllSame)
{
this->AppendData(newPts->GetData(),
inPts->GetData(), ptOffset);
}
else
{
this->AppendDifferentPoints(newPts->GetData(),
inPts->GetData(), ptOffset);
}
// copy scalars directly
if (newPtScalars)
{
this->AppendData(newPtScalars,inPD->GetScalars(), ptOffset);
}
// copy normals directly
if (newPtNormals)
{
this->AppendData(newPtNormals, inPD->GetNormals(), ptOffset);
}
// copy vectors directly
if (newPtVectors)
{
this->AppendData(newPtVectors, inPD->GetVectors(), ptOffset);
}
// copy tcoords directly
if (newPtTCoords)
{
this->AppendData(newPtTCoords, inPD->GetTCoords() , ptOffset);
}
// copy tensors directly
if (newPtTensors)
{
this->AppendData(newPtTensors, inPD->GetTensors(), ptOffset);
}
// append the remainder of the field data
for (ptId=0; ptId < numPts; ptId++)
{
outputPD->CopyData(ptList,inPD,countPD,ptId,ptId+ptOffset);
}
++countPD;
}
if (ds->GetNumberOfCells() > 0)
{
// These are the cellIDs at which each of the cell types start.
vtkIdType linesIndex = ds->GetNumberOfVerts();
vtkIdType polysIndex = linesIndex + ds->GetNumberOfLines();
vtkIdType stripsIndex = polysIndex + ds->GetNumberOfPolys();
// cell data could be made efficient like the point data,
// but I will wait on that.
// copy cell data
for (cellId=0; cellId < numCells; cellId++)
{
vtkIdType outCellId = 0;
if (cellId < linesIndex)
{
outCellId = vertOffset;
vertOffset++;
}
else if (cellId < polysIndex)
{
// outCellId = number of lines we already added + total number of
// verts expected in the output.
outCellId = linesOffset + numVerts;
linesOffset++;
}
else if (cellId < stripsIndex)
{
// outCellId = number of polys we already added + total number of
// verts and lines expected in the output.
outCellId = polysOffset + numLines + numVerts;
polysOffset++;
}
else
{
// outCellId = number of tstrips we already added + total number of
// polys, verts and lines expected in the output.
outCellId = stripsOffset + numPolys + numLines + numVerts;
stripsOffset++;
}
outputCD->CopyData(cellList,inCD,countCD,cellId,outCellId);
}
++countCD;
// copy the cells
pPolys = this->AppendCells(pPolys, inPolys, ptOffset);
// These other cell arrays could be made efficient like polys ...
for (inVerts->InitTraversal(); inVerts->GetNextCell(npts,pts); )
{
newVerts->InsertNextCell(npts);
for (i=0; i < npts; i++)
{
newVerts->InsertCellPoint(pts[i]+ptOffset);
}
}
for (inLines->InitTraversal(); inLines->GetNextCell(npts,pts); )
{
newLines->InsertNextCell(npts);
for (i=0; i < npts; i++)
{
newLines->InsertCellPoint(pts[i]+ptOffset);
}
}
for (inStrips->InitTraversal(); inStrips->GetNextCell(npts,pts); )
{
newStrips->InsertNextCell(npts);
for (i=0; i < npts; i++)
{
newStrips->InsertCellPoint(pts[i]+ptOffset);
}
}
}
ptOffset += numPts;
}
}
// Update ourselves and release memory
//
output->SetPoints(newPts);
newPts->Delete();
if (newPtScalars)
{
output->GetPointData()->SetScalars(newPtScalars);
newPtScalars->Delete();
}
if (newPtNormals)
{
output->GetPointData()->SetNormals(newPtNormals);
newPtNormals->Delete();
}
if (newPtVectors)
{
output->GetPointData()->SetVectors(newPtVectors);
newPtVectors->Delete();
}
if (newPtTCoords)
{
output->GetPointData()->SetTCoords(newPtTCoords);
newPtTCoords->Delete();
}
if (newPtTensors)
{
output->GetPointData()->SetTensors(newPtTensors);
newPtTensors->Delete();
}
if ( newVerts->GetNumberOfCells() > 0 )
{
output->SetVerts(newVerts);
}
newVerts->Delete();
if ( newLines->GetNumberOfCells() > 0 )
{
output->SetLines(newLines);
}
newLines->Delete();
if ( newPolys->GetNumberOfCells() > 0 )
{
output->SetPolys(newPolys);
}
newPolys->Delete();
if ( newStrips->GetNumberOfCells() > 0 )
{
output->SetStrips(newStrips);
}
newStrips->Delete();
// When all optimizations are complete, this squeeze will be unnecessary.
// (But it does not seem to cost much.)
output->Squeeze();
return 1;
}
其实代码的注释已经很明了了,这个做个简单的总结。
- 循环遍历输入 inputs, 统计非空数据集中可用的点集数目 countPD,和可用的单元(cell)数目 countCD,用于申请 vtkDataSetAttributes::FieldList 列表的长度;
- 统计输入数据的点集、单元信息:
- numPts: 所有多边形数据的点个数总和
- ptList :多边形数据集的点集列表
- sizePolys :
- numCells += ds->GetNumberOfCells();
// Count the cells of each type.
// This is used to ensure that cell data is copied at the correct locations in the output.
numVerts += ds->GetNumberOfVerts();
numLines += ds->GetNumberOfLines();
numPolys += ds->GetNumberOfPolys();
numStrips += ds->GetNumberOfStrips(); - cellList :多边形数据集的Cell列表
- numPts: 所有多边形数据的点个数总和
- 检查所有的点的类型是否相同,不同使用最高级类型; 确认输出点newPts的数据类型
- 为点的不同属性初始化变量:
- 数据集的属性vtkDataSetAttributes包括:
scalars, vectors, normals, texture coordinates, tensors, global ids, pedigree ids, and field data
标量 向量 法线 文理坐标 张量 全局ID 谱系ID(不知道) 字段数据
- 数据集的属性vtkDataSetAttributes包括:
- AppendData()、AppendCells()
void vtkAppendPolyData::AppendData(vtkDataArray *dest, vtkDataArray *src,
vtkIdType offset)
{
void *pSrc, *pDest;
vtkIdType length;
// sanity checks
if (src->GetDataType() != dest->GetDataType())
{
vtkErrorMacro("Data type mismatch.");
return;
}
if (src->GetNumberOfComponents() != dest->GetNumberOfComponents()) // 维度的判断
{
vtkErrorMacro("NumberOfComponents mismatch.");
return;
}
if (src->GetNumberOfTuples() + offset > dest->GetNumberOfTuples()) // Get the number of tuples (a component group) in the array
{
vtkErrorMacro("Destination not big enough");
return;
}
// convert from tuples to components.
offset *= src->GetNumberOfComponents();
length = src->GetMaxId() + 1;
switch (src->GetDataType())
{
vtkTemplateMacro(
length *= vtkAppendPolyDataGetTypeSize(static_cast<VTK_TT*>(0))
);
default:
vtkErrorMacro("Unknown data type " << src->GetDataType());
}
pSrc = src->GetVoidPointer(0);
pDest = dest->GetVoidPointer(offset);
memcpy(pDest, pSrc, length);
}
同理不同类型的数据扩充函数
void vtkAppendPolyData::AppendDifferentPoints(vtkDataArray *dest,
vtkDataArray *src,
vtkIdType offset)
在实现部分,需要注意的就是数据源的类型,进而影响 Length 的计算
④ AppendCells()
vtkIdType *vtkAppendPolyData::AppendCells(vtkIdType *pDest, vtkCellArray *src,
vtkIdType offset)
{
vtkIdType *pSrc, *end, *pNum;
if (src == NULL)
{
return pDest;
}
pSrc = src->GetPointer();
end = pSrc + src->GetNumberOfConnectivityEntries();
pNum = pSrc;
while (pSrc < end)
{
if (pSrc == pNum)
{
// move cell pointer to next cell
pNum += 1+*pSrc;
// copy the number of cells
*pDest++ = *pSrc++;
}
else
{
// offset the point index
*pDest++ = offset + *pSrc++;
}
}
return pDest;
}
【简介】
将一个或多个的数据集连接整一个单独的非结构化网格(存储空间大,计算耗时)