Hello,<div><br></div><div>I have a voxel type terrain/height map updated at 1Hz. At first I tried using glyphs for the cells, which (un-surprisingly) turned out to be too slow. I re-wrote it today to use cells of triangle strips. I have been hitting my head on the wall with memory leaks, and after scouring the c++ examples I am almost to the point of scrapping everything and running back to direct openGL. </div>
<div><br></div><div>As the number of cells, points, etc are constant, I thought it would be possible to declare things as vtkSmartPointer<> kept as class members. This works for the points data (points,normals, colors), but if I try it with anything else (such as vtkcellarray, vtkPolyDataMapper, or vtkPolyData), i see huge memory leaks. the leak from polydata was really weird</div>
<div><br></div><div>Would someone please look at the code below and tell me what i'm missing? If i understand the book and tutorials, i should be able to just create everything once and then update the data arrays... is there some sort of a cleanup method I should be calling on each update? (also recommendations on how to use less memory would be appreciated)</div>
<div><br></div><div>for reference a "MapHandle" is a boost::shared_ptr<Map>, where Map is a vector of Cells. Map also has convenience methods to convert from iterators to/from x.y.z points.</div><div><br></div>
<div><div> class MapActor</div><div> {</div><div> public:</div><div><br></div><div> MapActor();</div><div> ~MapActor();</div><div><br></div><div> void updateMap(MapHandle handle, ColorMap &objectColors, bool heightColor = false);</div>
<div> </div><div> vtkActor * actorPointer() { return actor; };</div><div><br></div><div> private:</div><div><br></div><div> rframe::Timer updateTimer;</div><div> </div>
<div> vtkSmartPointer<vtkPoints> points;</div><div> vtkSmartPointer<vtkFloatArray> normals;</div><div> vtkSmartPointer<vtkUnsignedCharArray> colors;</div><div>
vtkSmartPointer<vtkPolyData> polydata;</div><div> vtkSmartPointer<vtkCellArray> celldata;</div><div> vtkSmartPointer<vtkPolyDataMapper> mapper;</div><div> vtkSmartPointer<vtkActor> actor;</div>
<div> vtkSmartPointer<vtkLookupTable> heightLut;</div><div><br></div><div> MapHandle mapHandle;</div><div> };</div></div><div><br></div><div><br></div><div><div>MapActor::MapActor() </div>
<div>{</div><div> polydata = vtkSmartPointer<vtkPolyData>::New();</div><div><br></div><div> // create empty polydata for now</div><div> polydata = vtkSmartPointer<vtkPolyData>::New();</div><div><br></div>
<div> heightLut = vtkSmartPointer<vtkLookupTable>::New();</div><div> heightLut->SetHueRange(0.6667,0.0);</div><div> // heightLut->SetTableRange(-3,10);</div><div> heightLut->SetTableRange(-1,1);</div>
<div> heightLut->Build();</div><div><br></div><div> actor = vtkSmartPointer<vtkActor>::New();</div><div>}</div><div><br></div><div><br></div><div>MapActor::~MapActor() </div><div>{</div><div>}</div><div><br>
</div><div><br></div><div>void MapActor::updateMap(MapHandle handle, ColorMap & objectColors, bool heightColor)</div><div>{</div><div> updateTimer.start();</div><div><br></div><div> mapHandle = handle;</div><div>
<br></div><div> // Create points</div><div> if (!points) </div><div> {</div><div> cout << "creating points" << endl;</div><div> points = vtkSmartPointer<vtkPoints>::New();</div>
<div> points->SetNumberOfPoints(mapHandle->size()*8);</div><div> }</div><div> </div><div> if (!normals)</div><div> {</div><div> normals = vtkSmartPointer<vtkFloatArray>::New();</div><div>
normals->SetNumberOfComponents(3);</div><div> normals->SetName("normals");</div><div> normals->SetNumberOfTuples(mapHandle->size()); </div><div> }</div><div><br></div>
<div> // if (!celldata)</div><div> {</div><div> celldata = vtkSmartPointer<vtkCellArray>::New(); // we want to create a new cell data every time, for garbage collection</div><div> // the docs say there is now way to pre-allocate celldata storage...</div>
<div> }</div><div><br></div><div> // add points for elevation cells</div><div> Point p;</div><div> float resolution = mapHandle->resolution();</div><div><br></div><div> VirtualMap::MapType::iterator it, endIt;</div>
<div> int cellCount = 0;</div><div> int pointCount = 0;</div><div> vtkIdType indicies[14];</div><div><br></div><div> it = mapHandle->begin();</div><div> endIt = mapHandle->end();</div><div><br></div><div>
double minZ, maxZ;</div><div> float normal[3];</div><div> double dcolor[3];</div><div> unsigned char color[3];</div><div><br></div><div> minZ = 999999;</div><div> maxZ = -999999;</div><div><br></div><div>
if (!colors)</div><div> {</div><div> colors = vtkSmartPointer<vtkUnsignedCharArray>::New();</div><div> colors->SetName("colors");</div><div> colors->SetNumberOfComponents(3);</div>
<div> colors->SetNumberOfTuples(mapHandle->size()*14);</div><div> }</div><div><br></div><div> while (it != endIt)</div><div> {</div><div> mapHandle->getPoint(p,it);</div><div><br></div><div>
float height = -1*it->height();</div><div> if (height <= 0) height = 0.01;</div><div><br></div><div> double z = -1*it->ground();</div><div><br></div><div> if (heightColor == true)</div>
<div> {</div><div> // set color</div><div> heightLut->GetColor(height,dcolor);</div><div> } </div><div> else</div><div> {</div><div> dcolor[0] = objectColors[it->classType()].red();</div>
<div> dcolor[1] = objectColors[it->classType()].green();</div><div> dcolor[2] = objectColors[it->classType()].blue();</div><div> }</div><div><br></div><div> color[0] = static_cast<unsigned char>(255.0 * dcolor[0]);</div>
<div> color[1] = static_cast<unsigned char>(255.0 * dcolor[1]);</div><div> color[2] = static_cast<unsigned char>(255.0 * dcolor[2]);</div><div> </div><div> // bottom front left</div>
<div> indicies[0] = pointCount;</div><div> points->SetPoint(pointCount,p.x(),-p.y(),z);</div><div> colors->InsertTupleValue(pointCount,color);</div><div> normal[0] = -1;</div><div> normal[1] = -1;</div>
<div> normal[2] = -1;</div><div> normals->InsertTupleValue(pointCount,normal);</div><div> pointCount++;</div><div> // top front left</div><div> indicies[1] = pointCount;</div><div> points->SetPoint(pointCount,p.x(),-p.y(),z+height);</div>
<div> colors->InsertTupleValue(pointCount,color);</div><div> normal[0] = -1;</div><div> normal[1] = -1;</div><div> normal[2] = 1;</div><div> normals->InsertTupleValue(pointCount,normal);</div>
<div> pointCount++;</div><div> // bottom front right</div><div> indicies[2] = pointCount;</div><div> points->SetPoint(pointCount,p.x()+resolution,-p.y(),z);</div><div> colors->InsertTupleValue(pointCount,color);</div>
<div> normal[0] = 1;</div><div> normal[1] = -1;</div><div> normal[2] = -1;</div><div> normals->InsertTupleValue(pointCount,normal);</div><div> pointCount++;</div><div> // top front right</div>
<div> indicies[3] = pointCount;</div><div> points->SetPoint(pointCount,p.x()+resolution,-p.y(),z+height);</div><div> colors->InsertTupleValue(pointCount,color);</div><div> normal[0] = 1;</div>
<div> normal[1] = -1;</div><div> normal[2] = 1;</div><div> normals->InsertTupleValue(pointCount,normal);</div><div> pointCount++;</div><div> // bootom back right</div><div> indicies[4] = pointCount;</div>
<div> points->SetPoint(pointCount,p.x()+resolution,-p.y()-resolution,z); // <- should this be -resolution?</div><div> colors->InsertTupleValue(pointCount,color);</div><div> normal[0] = 1;</div>
<div> normal[1] = 1;</div><div> normal[2] = -1;</div><div> normals->InsertTupleValue(pointCount,normal);</div><div> pointCount++;</div><div> // top back right</div><div> indicies[5] = pointCount;</div>
<div> points->SetPoint(pointCount,p.x()+resolution,-p.y()-resolution,z+height);</div><div> colors->InsertTupleValue(pointCount,color);</div><div> normal[0] = 1;</div><div> normal[1] = 1;</div>
<div> normal[2] = 1;</div><div> normals->InsertTupleValue(pointCount,normal);</div><div> pointCount++;</div><div> // bottom back left</div><div> indicies[6] = pointCount;</div><div> points->SetPoint(pointCount,p.x(),-p.y()-resolution,z);</div>
<div> colors->InsertTupleValue(pointCount,color);</div><div> normal[0] = -1;</div><div> normal[1] = 1;</div><div> normal[2] = -1;</div><div> normals->InsertTupleValue(pointCount,normal);</div>
<div> pointCount++;</div><div> // top back left</div><div> indicies[7] = pointCount;</div><div> points->SetPoint(pointCount,p.x(),-p.y()-resolution,z+height);</div><div> colors->InsertTupleValue(pointCount,color);</div>
<div> normal[0] = -1;</div><div> normal[1] = 1;</div><div> normal[2] = 1;</div><div> normals->InsertTupleValue(pointCount,normal);</div><div> pointCount++;</div><div><br></div><div> // close box</div>
<div> indicies[8] = indicies[0];</div><div> indicies[9] = indicies[1];</div><div> // add top</div><div> // degenerate triangle</div><div> indicies[10] = indicies[1];</div><div> indicies[11] = indicies[7];</div>
<div> indicies[12] = indicies[3];</div><div> indicies[13] = indicies[5];</div><div><br></div><div> // indicies[12] = ;</div><div> </div><div> // celldata->InsertNextCell(triangleStrip);</div>
<div> celldata->InsertNextCell(14,indicies);</div><div> </div><div> if (height < minZ) minZ = height;</div><div> if (height > maxZ) maxZ = height;</div><div> </div><div> ++it;</div>
<div> ++cellCount;</div><div> }</div><div><br></div><div> polydata = vtkSmartPointer<vtkPolyData>::New();</div><div><br></div><div> polydata->SetPoints(points);</div><div> polydata->GetPointData()->SetNormals(normals);</div>
<div> polydata->SetStrips(celldata);</div><div><br></div><div> // polydata->Update();</div><div> // polydata->GetCellData()->SetScalars(colors); well this doesn't work right... </div><div> polydata->GetPointData()->SetScalars(colors);</div>
<div> polydata->Modified();</div><div><br></div><div> // Create a mapper and actor</div><div> // if (!mapper)</div><div> {</div><div> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();</div>
<div> }</div><div><br></div><div> //mapper->SetInputConnection(glyph3D->GetOutputPort());</div><div> mapper->SetInput(polydata);</div><div><br></div><div> actor->SetMapper(mapper);</div><div> // actor->GetProperty()->BackfaceCullingOn();</div>
<div><br></div><div> updateTimer.stop();</div><div><br></div><div> cout << "map update took: " << updateTimer.elapsedDouble() << ", avg: " << updateTimer.averageElapsedDouble() << endl;</div>
<div>}</div></div><div><br></div><div><br></div>