Esempio n. 1
0
void getSubDTimeSpan(ISubD iSub, chrono_t& first, chrono_t& last) {

	ISubDSchema mesh = iSub.getSchema();
	TimeSamplingPtr ts = mesh.getTimeSampling();
	first = std::min(first, ts->getSampleTime(0) );
	last = std::max(last, ts->getSampleTime(mesh.getNumSamples()-1) );
}
//-*****************************************************************************
void getABCTimeSpan(IArchive archive, chrono_t& first, chrono_t& last)
{
	// TO DO: Is the childBounds property reliable to get the full archive's span?

	if (!archive.valid())
		return;

	IObject archiveTop = archive.getTop();
    if ( archiveTop.getProperties().getPropertyHeader( ".childBnds" ) != NULL ) { // Try to get timing from childBounds first

        IBox3dProperty childbnds = Alembic::Abc::IBox3dProperty( archive.getTop().getProperties(),
                                   ".childBnds", ErrorHandler::kQuietNoopPolicy); 
    	TimeSamplingPtr ts = childbnds.getTimeSampling();
		first = std::min(first, ts->getSampleTime(0) );
		last = std::max(last, ts->getSampleTime(childbnds.getNumSamples()-1) );
        return;
    }

	unsigned int numChildren = archiveTop.getNumChildren();

	for (unsigned i=0; i<numChildren; ++i)  // Visit every object to get its first and last sample
	{
		IObject obj( archiveTop.getChild( i ));
		getObjectTimeSpan(obj, first, last, true);

	}

}
Esempio n. 3
0
void getCameraTimeSpan(ICamera iCam, chrono_t& first, chrono_t& last) {

	ICameraSchema cam = iCam.getSchema();
	TimeSamplingPtr ts = cam.getTimeSampling();
	first = std::min(first, ts->getSampleTime(0) );
	last = std::max(last, ts->getSampleTime(cam.getNumSamples()-1) );
}
//-*****************************************************************************
ISubDDrw::ISubDDrw( ISubD &iPmesh )
  : IObjectDrw( iPmesh, false )
  , m_subD( iPmesh )
{
    // Get out if problems.
    if ( !m_subD.valid() )
    {
        return;
    }


    // The object has already set up the min time and max time of
    // all the children.
    // if we have a non-constant time sampling, we should get times
    // out of it.
    TimeSamplingPtr iTsmp = m_subD.getSchema().getTimeSampling();
    if ( !m_subD.getSchema().isConstant() )
    {
        size_t numSamps =  m_subD.getSchema().getNumSamples();
        if ( numSamps > 0 )
        {
            chrono_t minTime = iTsmp->getSampleTime( 0 );
            m_minTime = std::min( m_minTime, minTime );
            chrono_t maxTime = iTsmp->getSampleTime( numSamps-1 );
            m_maxTime = std::max( m_maxTime, maxTime );
        }
    }
}
void getXformTimeSpan(IXform iXf, chrono_t& first, chrono_t& last, bool inherits) {

	IXformSchema xf = iXf.getSchema();
	TimeSamplingPtr ts = xf.getTimeSampling();
	first = std::min(first, ts->getSampleTime(0) );
	if (xf.isConstant()) {
		last = first;
	}
	else {
		last = std::max(last, ts->getSampleTime(xf.getNumSamples()-1) );
	}
	if (inherits && xf.getInheritsXforms()) {
		IObject parent = iXf.getParent();

		// Once the Archive's Top Object is reached, IObject::getParent() will
		// return an invalid IObject, and that will evaluate to False.
		while ( parent )
		{
			if ( Alembic::AbcGeom::IXform::matches(parent.getHeader()) ) {
				IXform x( parent, kWrapExisting );
				getXformTimeSpan(x, first, last, inherits);
			}
		}

	}
}
//-*****************************************************************************
IPolyMeshDrw::IPolyMeshDrw( IPolyMesh &iPmesh, std::vector<std::string> path )
  : IObjectDrw( iPmesh, false, path )
  , m_polyMesh( iPmesh )
{
    // Get out if problems.
    if ( !m_polyMesh.valid() )
    {
        return;
    }

    if ( m_polyMesh.getSchema().getNumSamples() > 0 )
    {
        m_polyMesh.getSchema().get( m_samp );
    }

    m_boundsProp = m_polyMesh.getSchema().getSelfBoundsProperty();

    // The object has already set up the min time and max time of
    // all the children.
    // if we have a non-constant time sampling, we should get times
    // out of it.
    TimeSamplingPtr iTsmp = m_polyMesh.getSchema().getTimeSampling();
    if ( !m_polyMesh.getSchema().isConstant() )
    {
        size_t numSamps =  m_polyMesh.getSchema().getNumSamples();
        if ( numSamps > 0 )
        {
            chrono_t minTime = iTsmp->getSampleTime( 0 );
            m_minTime = std::min( m_minTime, minTime );
            chrono_t maxTime = iTsmp->getSampleTime( numSamps-1 );
            m_maxTime = std::max( m_maxTime, maxTime );
        }
    }
    m_drwHelper.setName(m_object.getFullName());
}
Esempio n. 7
0
/**
 * init
 */
bool UMAbcNurbsPatch::init(bool recursive)
{
	if (!is_valid()) return false;
	
	// // create our nurb renderer.
	// nurb = gluNewNurbsRenderer();

	// gluNurbsProperty(nurb, GLU_SAMPLING_TOLERANCE, 25.0);
	// gluNurbsProperty(nurb, GLU_DISPLAY_MODE, GLU_FILL);

	size_t num_samples = patch_.getSchema().getNumSamples();
	if (num_samples > 0)
	{
		// get constant sample
		patch_.getSchema().get(initial_sample_);
		
		// if not consistant, we get time
		if (!patch_.getSchema().isConstant())
		{
			TimeSamplingPtr time = patch_.getSchema().getTimeSampling();
			min_time_ = static_cast<unsigned long>(time->getSampleTime(0)*1000);
			max_time_ = static_cast<unsigned long>(time->getSampleTime(num_samples-1)*1000);
		}
	}

	return false;
}
Esempio n. 8
0
void getPolyMeshTimeSpan(IPolyMesh iPoly, chrono_t& first, chrono_t& last) {

	IPolyMeshSchema mesh = iPoly.getSchema();
	TimeSamplingPtr ts = mesh.getTimeSampling();
	first = std::min(first, ts->getSampleTime(0) );
	last = std::max(last, ts->getSampleTime(mesh.getNumSamples()-1) );
}
Esempio n. 9
0
//-*****************************************************************************
INuPatchDrw::INuPatchDrw( INuPatch &iNuPatch )
  : IObjectDrw( iNuPatch, false )
  , m_nuPatch( iNuPatch )
{
    // create our nurb renderer.
    nurb = gluNewNurbsRenderer();

    gluNurbsProperty(nurb, GLU_SAMPLING_TOLERANCE, 25.0);
    gluNurbsProperty(nurb, GLU_DISPLAY_MODE, GLU_FILL);

    // Get out if problems.
    if ( !m_nuPatch.valid() )
    {
        return;
    }


    // The object has already set up the min time and max time of
    // all the children.
    // if we have a non-constant time sampling, we should get times
    // out of it.
    TimeSamplingPtr iTsmp = m_nuPatch.getSchema().getTimeSampling();
    if ( !m_nuPatch.getSchema().isConstant() )
    {
        size_t numSamps = m_nuPatch.getSchema().getNumSamples();
        if ( numSamps > 0 )
        {
            chrono_t minTime = iTsmp->getSampleTime( 0 );
            m_minTime = std::min( m_minTime, minTime );
            chrono_t maxTime = iTsmp->getSampleTime( numSamps-1 );
            m_maxTime = std::max( m_maxTime, maxTime );
        }
    }
}
Esempio n. 10
0
void ofxAlembic::IGeom::update_timestamp(T& object)
{
	TimeSamplingPtr iTsmp = object.getSchema().getTimeSampling();
	if (!object.getSchema().isConstant())
	{
		size_t numSamps =  object.getSchema().getNumSamples();
		if (numSamps > 0)
		{
			m_minTime = iTsmp->getSampleTime(0);
			m_maxTime = iTsmp->getSampleTime(numSamps - 1);
		}
	}
}
//-*****************************************************************************
void simpleTestIn( const std::string &iArchiveName )
{
    IArchive archive( Alembic::AbcCoreHDF5::ReadArchive(),
                      iArchiveName, ErrorHandler::kThrowPolicy );

    IObject archiveTop = archive.getTop();
    IObject c0( archiveTop, "c0" );
    ICompoundProperty c0Props = c0.getProperties();

    TimeSamplingPtr uts = c0Props.getPtr()->
        getScalarProperty( "uniformdoubleprop" )->getTimeSampling();

    TimeSamplingPtr ats = c0Props.getPtr()->
        getScalarProperty( "acyclicdoubleprop" )->getTimeSampling();

    //IDoubleProperty dp0( c0Props, "uniformdoubleprop" );
    //IDoubleProperty dp1( c0Props, "acyclicdoubleprop" );
    //size_t numReadDoubleSamps = dp0.getNumSamples();
    //TESTING_ASSERT( numReadDoubleSamps == g_numDoubleSamps );
    //TESTING_ASSERT( dp1.getNumSamples() == numReadDoubleSamps );


    //scramble_heap();

    //const TimeSamplingType &utst = uts.getTimeSamplingType();
    const TimeSamplingType utst = c0Props.getPtr()->getScalarProperty(
        "uniformdoubleprop" )->getTimeSampling()->getTimeSamplingType();

    for ( size_t j = 0 ; j < g_numDoubleSamps ; j++ )
    {
        chrono_t utime = uts->getSampleTime( j );
        chrono_t atime = ats->getSampleTime( j );

        chrono_t reftime = g_doubleStartTime + ( j * g_dt );

        std::cout << "reference time: " << reftime << std::endl;

        std::cout << "uniform sample time: " << utime << std::endl;

        std::cout << "acyclic sample time: " << atime << std::endl;

        chrono_t ABSERROR = 0.00001;

        TESTING_ASSERT( Imath::equalWithAbsError( utime, reftime, ABSERROR ) );
        TESTING_ASSERT( Imath::equalWithAbsError( atime, reftime, ABSERROR ) );
        TESTING_ASSERT( Imath::equalWithAbsError( atime, utime, ABSERROR ) );
    }
}
ofxAlembic::IXform::IXform(Alembic::AbcGeom::IXform object) : ofxAlembic::IGeom(object), m_xform(object)
{
	TimeSamplingPtr iTsmp = m_xform.getSchema().getTimeSampling();
	if (!m_xform.getSchema().isConstant())
	{
		size_t numSamps =  m_xform.getSchema().getNumSamples();
		if (numSamps > 0)
		{
			chrono_t minTime = iTsmp->getSampleTime(0);
			m_minTime = std::min(m_minTime, minTime);
			chrono_t maxTime = iTsmp->getSampleTime(numSamps - 1);
			m_maxTime = std::max(m_maxTime, maxTime);
		}
	}
	
	type = XFORM;
}
ofxAlembic::IPolyMesh::IPolyMesh(Alembic::AbcGeom::IPolyMesh object) : ofxAlembic::IGeom(object), m_polyMesh(object)
{
	TimeSamplingPtr iTsmp = m_polyMesh.getSchema().getTimeSampling();
	if (!m_polyMesh.getSchema().isConstant())
	{
		size_t numSamps =  m_polyMesh.getSchema().getNumSamples();
		if (numSamps > 0)
		{
			chrono_t minTime = iTsmp->getSampleTime(0);
			m_minTime = std::min(m_minTime, minTime);
			chrono_t maxTime = iTsmp->getSampleTime(numSamps - 1);
			m_maxTime = std::max(m_maxTime, maxTime);
		}
	}

	type = POLYMESH;
}
ofxAlembic::ICurves::ICurves(Alembic::AbcGeom::ICurves object) : ofxAlembic::IGeom(object), m_curves(object)
{

	TimeSamplingPtr iTsmp = m_curves.getSchema().getTimeSampling();
	if (!object.getSchema().isConstant())
	{
		size_t numSamps = object.getSchema().getNumSamples();
		if (numSamps > 0)
		{
			chrono_t minTime = iTsmp->getSampleTime(0);
			m_minTime = std::min(m_minTime, minTime);
			chrono_t maxTime = iTsmp->getSampleTime(numSamps - 1);
			m_maxTime = std::max(m_maxTime, maxTime);
		}
	}

	type = CURVES;
}
Esempio n. 15
0
//-*****************************************************************************
IPointsDrw::IPointsDrw( IPoints &iPmesh )
    : IObjectDrw( iPmesh, false )
    , m_points( iPmesh )
{
    // Get out if problems.
    if ( !m_points.valid() )
    {
        return;
    }

    // Try to create colors, if possible.
    IPointsSchema &pointsSchema = m_points.getSchema();
    const PropertyHeader *phead = pointsSchema.getPropertyHeader( "Cs" );
    if ( phead && IC3fArrayProperty::matches( *phead ) )
    {
        m_colorProp = IC3fArrayProperty( pointsSchema, "Cs" );
    }

    phead = pointsSchema.getPropertyHeader( "N" );
    if ( phead && IN3fArrayProperty::matches( *phead ) )
    {
        m_normalProp = IN3fArrayProperty( pointsSchema, "N" );
    }

    // The object has already set up the min time and max time of
    // all the children.
    // if we have a non-constant time sampling, we should get times
    // out of it.
    TimeSamplingPtr iTsmp = m_points.getSchema().getTimeSampling();
    if ( !m_points.getSchema().isConstant() )
    {
        size_t numSamps =  m_points.getSchema().getNumSamples();
        if ( numSamps > 0 )
        {
            chrono_t minTime = iTsmp->getSampleTime( 0 );
            m_minTime = std::min( m_minTime, minTime );
            chrono_t maxTime = iTsmp->getSampleTime( numSamps-1 );
            m_maxTime = std::max( m_maxTime, maxTime );
        }
    }
}
Esempio n. 16
0
void readProperty(const std::string &archiveName, bool useOgawa)
{
    // Open an existing archive for reading. Indicate that we want
    //   Alembic to throw exceptions on errors.
    std::cout  << "Reading " << archiveName << std::endl;
    AbcF::IFactory factory;
    factory.setPolicy(  ErrorHandler::kThrowPolicy );
    AbcF::IFactory::CoreType coreType;
    IArchive archive = factory.getArchive(archiveName, coreType);
    ABCA_ASSERT( (useOgawa && coreType == AbcF::IFactory::kOgawa) ||
                    (!useOgawa && coreType == AbcF::IFactory::kHDF5),
                  "File did not open as the expected type." );

    IObject archiveTop = archive.getTop();

    // Determine the number of (top level) children the archive has
    const unsigned int numChildren =  archiveTop.getNumChildren();
    ABCA_ASSERT( numChildren == 1, "Wrong number of children (expected 1)");
    std::cout << "The archive has " << numChildren << " children:"
              << std::endl;


    // Iterate through them, print out their names
    IObject child( archiveTop, archiveTop.getChildHeader( 0 ).getName() );
    std::cout << "  " << child.getName();


    // Properties
    ICompoundProperty props = child.getProperties();
    size_t numProperties = props.getNumProperties();  // only top-level props
    ABCA_ASSERT( numProperties == 1,
                 "Expected 1 property, found " << numProperties);
    std::cout << " with one property";


    std::vector<std::string> propNames(1);
    propNames[0] = props.getPropertyHeader(0).getName();
    std::cout << " named " << propNames[0] << std::endl;

    PropertyType pType = props.getPropertyHeader(0).getPropertyType();
    ABCA_ASSERT( pType == kScalarProperty,
                 "Expected a scalar property, but didn't find one" );

    std::cout << " which is a scalar property";



    DataType dType = props.getPropertyHeader(0).getDataType();
    ABCA_ASSERT( dType.getPod() == kFloat64POD,
                 "Expected a double (kFloat64POD) property, but didn't"
                 " find one" );

    // We know this is a scalar property (I'm eliding the if/else
    //  statements required to recognize this)
    IDoubleProperty mass( props, propNames[0] );

    size_t numSamples = mass.getNumSamples();
    std::cout << ".. it has " << numSamples << " samples" << std::endl;
    //ABCA_ASSERT( numSamples == 5, "Expected 5 samples, found " << numSamples );

    TimeSamplingPtr ts = mass.getTimeSampling();

    std::cout << "..with time/value pairs: ";
    for (unsigned int ss=0; ss<numSamples; ss++)
    {
        ISampleSelector iss( (index_t) ss);
        std::cout << ts->getSampleTime( (index_t) ss ) << "/";
        printSampleValue( mass, iss );
        std::cout << " ";

        double timeDiff = ts->getSampleTime( (index_t) ss ) -
            (g_startTime + (ss*(g_dt/3.0)));
        ABCA_ASSERT( fabs(timeDiff) < 1e-12, "Incorrect sample time read" );


        double massDiff = mass.getValue( iss ) - (1.0 + 0.1*ss);
        ABCA_ASSERT( fabs(massDiff) < 1e-12, "Incorrect sample value read" );
    }
    ABCA_ASSERT(
        archive.getMaxNumSamplesForTimeSamplingIndex(1) == (index_t) numSamples,
        "Incorrect number of max samples for Time Sampling ID 1.");
    std::cout << std::endl;

    // Done - the archive closes itself
}
//-*****************************************************************************
void GetRelevantSampleTimes( ProcArgs &args, TimeSamplingPtr timeSampling,
                            size_t numSamples, SampleTimeSet &output )
{
    if ( numSamples < 2 )
    {
        output.insert( 0.0 );
        return;
    }

    chrono_t frameTime = args.frame / args.fps;

    chrono_t shutterOpenTime = ( args.frame + args.shutterOpen ) / args.fps;

    chrono_t shutterCloseTime = ( args.frame + args.shutterClose ) / args.fps;

    std::pair<index_t, chrono_t> shutterOpenFloor =
        timeSampling->getFloorIndex( shutterOpenTime, numSamples );

    std::pair<index_t, chrono_t> shutterCloseCeil =
        timeSampling->getCeilIndex( shutterCloseTime, numSamples );

    //TODO, what's a reasonable episilon?
    static const chrono_t epsilon = 1.0 / 10000.0;

    //check to see if our second sample is really the
    //floor that we want due to floating point slop
    //first make sure that we have at least two samples to work with
    if ( shutterOpenFloor.first < shutterCloseCeil.first )
    {
        //if our open sample is less than open time,
        //look at the next index time
        if ( shutterOpenFloor.second < shutterOpenTime )
        {
            chrono_t nextSampleTime =
                     timeSampling->getSampleTime( shutterOpenFloor.first + 1 );

            if ( fabs( nextSampleTime - shutterOpenTime ) < epsilon )
            {
                shutterOpenFloor.first += 1;
                shutterOpenFloor.second = nextSampleTime;
            }
        }
    }


    for ( index_t i = shutterOpenFloor.first; i < shutterCloseCeil.first; ++i )
    {
        output.insert( timeSampling->getSampleTime( i ) );
    }

    //no samples above? put frame time in there and get out
    if ( output.size() == 0 )
    {
        output.insert( frameTime );
        return;
    }

    chrono_t lastSample = *(output.rbegin() );

    //determine whether we need the extra sample at the end
    if ( ( fabs( lastSample - shutterCloseTime ) > epsilon )
         && lastSample < shutterCloseTime )
    {
        output.insert( shutterCloseCeil.second );
    }
}
Esempio n. 18
0
void readSimpleProperties(const std::string &archiveName)
{
    // Open an existing archive for reading. Indicate that we want
    //   Alembic to throw exceptions on errors.
    AbcF::IFactory factory;
    factory.setPolicy(  ErrorHandler::kThrowPolicy );
    AbcF::IFactory::CoreType coreType;
    IArchive archive = factory.getArchive(archiveName, coreType);
    IObject archiveTop = archive.getTop();

    // Determine the number of (top level) children the archive has
    const int numChildren = archiveTop.getNumChildren();
    TESTING_ASSERT( numChildren == 4 );
    std::cout << "The archive has " << numChildren << " children:"
              << std::endl;

    // Iterate through them, print out their names
    for (int ii=0; ii<numChildren; ii++)
    {
        IObject child( archiveTop, archiveTop.getChildHeader( ii ).getName() );
        std::cout << "  " << child.getName();

        std::cout << " has " << child.getNumChildren() << " children"
                  << std::endl;

        // Properties
        ICompoundProperty props = child.getProperties();
        int numProperties = props.getNumProperties();

        std::cout << "  ..and " << numProperties << " simple properties"
                  << std::endl;

        std::vector<std::string> propNames;
        for (int pp=0; pp<numProperties; pp++)
            propNames.push_back( props.getPropertyHeader(pp).getName() );

        for (int jj=0; jj<numProperties; jj++)
        {
            std::cout << "    ..named " << propNames[jj] << std::endl;

            std::cout << "    ..with type: ";
            PropertyType pType = props.getPropertyHeader(jj).getPropertyType();
            if (pType == kCompoundProperty)
            {
                std::cout << "compound" << std::endl;
            }
            else if (pType == kScalarProperty)
            {
                std::cout << "scalar" << std::endl;
            }
            else if (pType == kArrayProperty)
            {
                std::cout << "array" << std::endl;
            }

            DataType dType = props.getPropertyHeader(jj).getDataType();
            std::cout << "    ..with POD-type: ";

            switch (dType.getPod())
            {
                case  kBooleanPOD:
                    std::cout << "boolean" << std::endl;
                    break;

                // Char/UChar
                case kUint8POD:
                    std::cout << "unsigned char" << std::endl;
                    break;
                case kInt8POD:
                    std::cout << "char" << std::endl;
                    break;

                // Short/UShort
                case kUint16POD:
                    std::cout << "short unsigned int" << std::endl;
                    break;
                case kInt16POD:
                    std::cout << "short int" << std::endl;
                    break;

                // Int/UInt
                case kUint32POD:
                    std::cout << "unsigned int" << std::endl;
                    break;
                case kInt32POD:
                    std::cout << "int" << std::endl;
                    break;

                // Long/ULong
                case kUint64POD:
                    std::cout << "unsigned long int" << std::endl;
                    break;
                case kInt64POD:
                    std::cout << "long int" << std::endl;
                    break;

                // Half/Float/Double
                case kFloat16POD:
                    std::cout << "half" << std::endl;
                    break;
                case kFloat32POD:
                    std::cout << "float" << std::endl;
                    break;
                case kFloat64POD:
                    std::cout << "double" << std::endl;
                    break;

                case kStringPOD:
                    std::cout << "string" << std::endl;
                    break;

                case kUnknownPOD:
                default:
                    std::cout << " Unknown! (this is bad)" << std::endl;
            };

            TimeSamplingPtr ts =
                GetCompoundPropertyReaderPtr(props)->
                getScalarProperty( propNames[jj] )->getTimeSampling();

            int numSamples = ts->getNumStoredTimes();


            std::cout << "    ..and "
                      << ts->getTimeSamplingType() << std::endl
                      << "    ..and " << numSamples << " samples at times: ";

            if (numSamples > 0)
            {
                std::cout << " ( ";
                for (int ss=0; ss<numSamples; ss++)
                    std::cout << ts->getSampleTime(ss) << " ";
                std::cout << ")";
            }
            std::cout << std::endl;

            std::cout << "    ..and values: ";
            if (numSamples > 0)
            {
                for (int ss=0; ss<numSamples; ss++)
                {
                    ISampleSelector iss( (index_t) ss);
                    switch (dType.getPod())
                    {
                        // Boolean
                        case  kBooleanPOD:
                        {
                            IBoolProperty prop( props,  propNames[jj] );
                            printSampleValue( prop, iss );
                            break;
                        }

                        // Char/UChar
                        case kUint8POD:
                        {
                            IUcharProperty prop( props,  propNames[jj] );
                            printSampleValue( prop, iss );
                            break;
                        }
                        case kInt8POD:
                        {
                            ICharProperty prop( props,  propNames[jj] );
                            printSampleValue( prop, iss );
                            break;
                        }

                        // Short/UShort
                        case kUint16POD:
                        {
                            IUInt16Property prop( props,  propNames[jj] );
                            printSampleValue( prop, iss );
                            break;
                        }
                        case kInt16POD:
                        {
                            IInt16Property prop( props,  propNames[jj] );
                            printSampleValue( prop, iss );
                            break;
                        }

                        // Int/UInt
                        case kUint32POD:
                        {
                            IUInt32Property prop( props,  propNames[jj] );
                            printSampleValue( prop, iss );
                            break;
                        }
                        case kInt32POD:
                        {
                            IInt32Property prop( props,  propNames[jj] );
                            printSampleValue( prop, iss );
                            break;
                        }

                        // Long/ULong
                        case kUint64POD:
                        {
                            IUInt64Property prop( props,  propNames[jj] );
                            printSampleValue( prop, iss );
                            break;
                        }
                        case kInt64POD:
                        {
                            IInt64Property prop( props,  propNames[jj] );
                            printSampleValue( prop, iss );
                            break;
                        }

                        // Half/Float/Double
                        case kFloat16POD:
                            // iostream doesn't understand float_16's
                            //printSampleValue( IHalfProperty( props,  propNames[jj] ),
                            //                  iss );
                            break;
                        case kFloat32POD:
                        {
                            IFloatProperty prop( props,  propNames[jj] );
                            printSampleValue( prop, iss );
                            break;
                        }
                        case kFloat64POD:
                        {
                            IDoubleProperty prop( props,  propNames[jj] );
                            printSampleValue( prop, iss );
                            break;
                        }

                        case kUnknownPOD:
                        default:
                            std::cout << " Unknown! (this is bad)" << std::endl;
                    };

                }
            }
            std::cout << std::endl;



            std::cout << std::endl; // done parsing property
        }
    }

    // Done - the archive closes itself
}
void readV3fArrayProperty(const std::string &archiveName, bool useOgawa)
{
    // Open an existing archive for reading. Indicate that we want
    //   Alembic to throw exceptions on errors.
    std::cout  << "Reading " << archiveName << std::endl;
    AbcF::IFactory factory;
    factory.setPolicy(  ErrorHandler::kThrowPolicy );
    AbcF::IFactory::CoreType coreType;
    IArchive archive = factory.getArchive(archiveName, coreType);
    TESTING_ASSERT( (useOgawa && coreType == AbcF::IFactory::kOgawa) ||
                    (!useOgawa && coreType == AbcF::IFactory::kHDF5) );

    IObject archiveTop = archive.getTop();

    // Determine the number of (top level) children the archive has
    const unsigned int numChildren =  archiveTop.getNumChildren();
    ABCA_ASSERT( numChildren == 1, "Wrong number of children (expected 1)");
    std::cout << "The archive has " << numChildren << " children:"
              << std::endl;

    // Iterate through them, print out their names
    IObject child( archiveTop, archiveTop.getChildHeader(0).getName() );
    std::cout << "  named '" << child.getName() << "'";

    // Properties
    ICompoundProperty props = child.getProperties();
    size_t numProperties = props.getNumProperties();  // only top-level props
    ABCA_ASSERT( numProperties == 1,
                 "Expected 1 property, found " << numProperties);
    std::cout << " with one property";

    std::vector<std::string> propNames(1);
    propNames[0] = props.getPropertyHeader(0).getName();
    std::cout << " named '" << propNames[0] << "'" << std::endl;


    PropertyType pType = props.getPropertyHeader(0).getPropertyType();
    ABCA_ASSERT( pType == kArrayProperty,
                 "Expected an array property, but didn't find one" );

    std::cout << " which is an array property";

    DataType dType = props.getPropertyHeader(0).getDataType();
    ABCA_ASSERT( dType.getPod() == kFloat32POD,
                 "Expected an v3f property, but didn't find one" );


    // We know this is an array property (I'm eliding the if/else
    //  statements required to recognize and handle this properly)
    IV3fArrayProperty positions( props, propNames[0] );
    size_t numSamples = positions.getNumSamples();
    std::cout << ".. it has " << numSamples << " samples" << std::endl;
    ABCA_ASSERT( numSamples == 5, "Expected 5 samples, found " << numSamples );

    TimeSamplingPtr ts = positions.getTimeSampling();
    std::cout << "..with time/value pairs: " << std::endl;;
    for (unsigned int ss=0; ss<numSamples; ss++)
    {
        std::cout << "   ";
        ISampleSelector iss( (index_t) ss);
        std::cout << ts->getSampleTime( (index_t) ss ) << " / ";

        V3fArraySamplePtr samplePtr;
        positions.get( samplePtr, iss );
        std::cout << "[ ";
        size_t numPoints = samplePtr->size();
        for ( size_t jj=0 ; jj<numPoints ; jj++ )
            std::cout << (*samplePtr)[jj] << " ";
        std::cout << "]" << std::endl;

        if (ss == 2) // no entries in sample #2
        {
            ABCA_ASSERT( numPoints == 0,
                         "Expected an empty sample, but found " << numPoints
                         << " entries." );
        }
        else
        {
            for ( size_t jj=0 ; jj<numPoints ; jj++ )
                ABCA_ASSERT( (*samplePtr)[jj] == g_vectors[jj],
                             "Incorrect value read from archive." );
        }

    }
    ABCA_ASSERT(
        archive.getMaxNumSamplesForTimeSamplingIndex(1) == (index_t) numSamples,
        "Incorrect number of max samples in readV3fArrayProperty." );
    std::cout << std::endl;
    // Done - the archive closes itself

    double start, end;
    GetArchiveStartAndEndTime( archive, start, end );

    TESTING_ASSERT( almostEqual(start, 123.0) );
    TESTING_ASSERT( almostEqual(end, 123.0 + 4.0 / 24.0) );
}