The library OpenCTM can be used to compress 3D data files. The new compressed file has only about 1/10 size compared with the original file.
We can use vertex property to store the model’s color which is often PointData’s scalar in VTK.
The following code snippet shows how to use OpenCTM to store polydata and color.
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(ctmExcise)
find_package( VTK REQUIRED )
include( ${VTK_USE_FILE} )
set( OPENCTM_LIB_DIR "/Users/weiyang/Downloads/OpenCTM-1.0.3/lib" )
include_directories( ${OPENCTM_LIB_DIR} )
link_directories( ${OPENCTM_LIB_DIR} )
message( "======> OPENCTM_LIB_DIR: ${OPENCTM_LIB_DIR}" )
add_executable( ${PROJECT_NAME} "main.cpp" "tool.h" )
# we need libopenctm.dylib
target_link_libraries( ${PROJECT_NAME} ${VTK_LIBRARIES} openctm )
main.cpp
#include <iostream>
#include <stdio.h>
#include <vtkSmartPointer.h>
#include <vtkSTLReader.h>
#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkCamera.h>
#include <vtkPolyData.h>
#include <string>
#include <vtkTriangleFilter.h>
#include <vtkSTLWriter.h>
#include <time.h>
#include <vtkSphereSource.h>
#include <vtkPointData.h>
#include <vtkDoubleArray.h>
#include "tool.h"
#include "openctmpp.h"
using namespace std;
void MySaveFile(CTMuint aVertCount, CTMuint aTriCount, CTMfloat * aVertices,
CTMuint * aIndices, const char * aFileName,
const CTMfloat * aAttribValues, const char * aName)
{
try
{
// Create a new OpenCTM exporter object
CTMexporter ctm;
// Define our mesh representation to OpenCTM (store references to it in
// the context)
ctm.DefineMesh(aVertices, aVertCount, aIndices, aTriCount, NULL);
ctm.AddAttribMap( aAttribValues, aName );
// Save the OpenCTM file
ctm.Save(aFileName);
}
catch(exception &e)
{
fprintf( stderr, "[%s, %d]: Error => %s\n", __FILE__, __LINE__, e.what( ) );
}
}
int main()
{
// -------------- OpenCTM save data ---------------
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->SetThetaResolution( 50 );
sphereSource->SetPhiResolution( 50 );
sphereSource->Update();
vtkPolyData *pd = sphereSource->GetOutput();
vtkPoints *points = pd->GetPoints();
vtkSmartPointer<vtkDoubleArray> scalars =
vtkSmartPointer<vtkDoubleArray>::New();
scalars->SetNumberOfTuples( points->GetNumberOfPoints() );
for(vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i)
{
scalars->SetTuple1(i, 1.0 * i / points->GetNumberOfPoints());
}
pd->GetPointData()->SetScalars( scalars );
CTMuint aVertCount = static_cast<unsigned int>( points->GetNumberOfPoints() );
CTMfloat *aVertices = new CTMfloat[3*aVertCount];
for( CTMuint i = 0; i < aVertCount; ++i )
{
PointStruct pt( points->GetPoint( i ) );
for( CTMuint j = 0; j < 3; ++j )
{
aVertices[3*i+j] = static_cast<CTMfloat>( pt[j] );
}
}
CTMuint aTriCount = static_cast<CTMuint>( pd->GetNumberOfCells() );
CTMuint *aIndices = new CTMuint[3*aTriCount];
for( CTMuint i = 0; i < aTriCount; ++i )
{
vtkIdList *ids = pd->GetCell( i )->GetPointIds();
for( CTMuint j = 0; j < 3; ++j )
{
aIndices[3*i+j] = static_cast<CTMuint>( ids->GetId( j ) );
}
}
CTMfloat *aScalars = new CTMfloat[aVertCount*4];
for( CTMuint i = 0; i < aVertCount; ++i )
{
aScalars[i*4] = scalars->GetValue( i );
}
string fileName = "./sphere.ctm";
MySaveFile( aVertCount, aTriCount, aVertices, aIndices, fileName.c_str(), aScalars, "aScalar" );
delete [] aVertices;
aVertices = nullptr;
delete [] aIndices;
aIndices = nullptr;
// -------------- Finish: OpenCTM save data ---------------
vtkSmartPointer<vtkPolyData> newPd = vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkCellArray> newCells = vtkSmartPointer<vtkCellArray>::New();
vtkSmartPointer<vtkDoubleArray> newScalars = vtkSmartPointer<vtkDoubleArray>::New();
CTMimporter ctm;
ctm.Load( fileName.c_str() );
CTMuint vertCount = ctm.GetInteger(CTM_VERTEX_COUNT);
const CTMfloat *vertices = ctm.GetFloatArray(CTM_VERTICES);
CTMuint triCount = ctm.GetInteger(CTM_TRIANGLE_COUNT);
const CTMuint *indices = ctm.GetIntegerArray(CTM_INDICES);
const CTMfloat *ctmScalars = ctm.GetFloatArray( CTM_ATTRIB_MAP_1 );
for( CTMuint i = 0; i < vertCount; ++i )
{
PointStruct pt;
for( int j = 0; j < 3; ++j )
{
pt[j] = vertices[3*i+j];
}
newPoints->InsertNextPoint( pt.point );
}
for( CTMuint i = 0; i < triCount; ++i )
{
vtkIdType cell[3];
for( int j = 0; j < 3; ++j )
{
cell[j] = indices[3*i+j];
}
newCells->InsertNextCell( 3, cell );
}
for( CTMuint i = 0; i < vertCount; ++i )
{
newScalars->InsertNextTuple1( ctmScalars[4*i] );
}
newPd->SetPoints( newPoints );
newPd->SetPolys( newCells );
newPd->GetPointData()->SetScalars( newScalars );
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData( newPd );
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper( mapper );
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->SetBackground( 0.1, 0.1, 0.1 );
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer( renderer );
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow( renderWindow );
renderer->ResetCamera();
renderWindow->Render();
renderWindowInteractor->Start();
return 0;
}