Exemple #1
0
Box3f Mesh::computeBounds() const {
    Box3f bounds;
    for (int i = 0; i < _vertices.cols(); ++i) {
        bounds.expandBy(_vertices.col(i));
    }
    return bounds;
}
Exemple #2
0
Imath::Box3f SceneNode::unionOfTransformedChildBounds( const ScenePath &path, const ScenePlug *out, const IECore::InternedStringVectorData *childNamesData ) const
{
	ConstInternedStringVectorDataPtr computedChildNames;
	if( !childNamesData )
	{
		computedChildNames = out->childNames( path );
		childNamesData = computedChildNames.get();
	}
	const vector<InternedString> &childNames = childNamesData->readable();

	Box3f result;
	if( childNames.size() )
	{
		ContextPtr tmpContext = new Context( *Context::current(), Context::Borrowed );
		Context::Scope scopedContext( tmpContext.get() );

		ScenePath childPath( path );
		childPath.push_back( InternedString() ); // room for the child name
		for( vector<InternedString>::const_iterator it = childNames.begin(); it != childNames.end(); it++ )
		{
			childPath[path.size()] = *it;
			tmpContext->set( ScenePlug::scenePathContextName, childPath );
			Box3f childBound = out->boundPlug()->getValue();
			childBound = transform( childBound, out->transformPlug()->getValue() );
			result.extendBy( childBound );
		}
	}
	return result;
}
Exemple #3
0
bool intersectRay( const Box3f& box,
    const Vector3f& rayOrigin, const Vector3f& rayDirection,
    float& tIntersect, float tMin )
{
    assert( box.isStandard() );
    assert( !box.isEmpty() );

    float tNear;
    float tFar;
    bool intersect = intersectLine( box, rayOrigin, rayDirection,
        tNear, tFar );
    if( intersect )
    {
        if( tNear >= tMin )
        {
            tIntersect = tNear;
        }
        else if( tFar >= tMin )
        {
            tIntersect = tFar;
        }
        else
        {
            intersect = false;
        }
    }
    return intersect;
}
Exemple #4
0
Imath::Box3f Group::computeBound( const ScenePath &path, const Gaffer::Context *context, const ScenePlug *parent ) const
{
	std::string groupName = namePlug()->getValue();

	if( path.size() <= 1 )
	{
		// either / or /groupName
		Box3f combinedBound;
		for( ScenePlugIterator it( inPlugs() ); it != it.end(); ++it )
		{
			// we don't need to transform these bounds, because the SceneNode
			// guarantees that the transform for root nodes is always identity.
			Box3f bound = (*it)->bound( ScenePath() );
			combinedBound.extendBy( bound );
		}
		if( path.size() == 0 )
		{
			combinedBound = transform( combinedBound, transformPlug()->matrix() );
		}
		return combinedBound;
	}
	else
	{
		const ScenePlug *sourcePlug = 0;
		ScenePath source = sourcePath( path, groupName, &sourcePlug );
		return sourcePlug->bound( source );
	}
}
bool Manipulator::canManipulate(Ray3f ray,Box3f box,Mat4f* T)
{
	//nothing to do
	if (!box.isValid())
		return false;

	Vec3f size=box.size();

	Mat4f Direct=(*T) * getTransformationToBox(box);
    Mat4f Inverse=Direct.invert();

    // the ray is in world coordinate
    Vec3f P1=Inverse * (ray.origin        );
    Vec3f P2=Inverse * (ray.origin+ray.dir);
    
    // should be the unit bounding ball not the bounding box, but seems good enough (probably better)
    // is objects does not overlap too much!
	float epsilon=1e-4f;
	Box3f unit_box(
		Vec3f(
			size[0]?-1:-epsilon,
			size[1]?-1:-epsilon,
			size[2]?-1:-epsilon),
		Vec3f(
			size[0]?+1:+epsilon,
			size[1]?+1:+epsilon,
			size[2]?+1:+epsilon));


	float tmin,tmax;
    return (Ray3f(P1,P2-P1).intersectBox(tmin,tmax,unit_box) && tmin>0);
}
Exemple #6
0
Imath::Box3f Instancer::computeBranchBound( const ScenePath &parentPath, const ScenePath &branchPath, const Gaffer::Context *context ) const
{
	ContextPtr ic = instanceContext( context, branchPath );
	if( ic )
	{
		Context::Scope scopedContext( ic );
		return instancePlug()->boundPlug()->getValue();
	}
	
	// branchPath == "/"
	
	Box3f result;
	ConstV3fVectorDataPtr p = sourcePoints( parentPath );
	if( p )
	{
		ScenePath branchChildPath( branchPath );
		branchChildPath.push_back( InternedString() ); // where we'll place the instance index
		for( size_t i=0; i<p->readable().size(); i++ )
		{
			/// \todo We could have a very fast InternedString( int ) constructor rather than all this lexical cast nonsense
			branchChildPath[branchChildPath.size()-1] = boost::lexical_cast<string>( i );
			Box3f branchChildBound = computeBranchBound( parentPath, branchChildPath, context );
			branchChildBound = transform( branchChildBound, computeBranchTransform( parentPath, branchChildPath, context ) );
			result.extendBy( branchChildBound );			
		}
	}

	return result;
}
Exemple #7
0
//-*****************************************************************************
void ReadParticles( const std::string &iFileName )
{
    IArchive archive( Alembic::AbcCoreOgawa::ReadArchive(),
                      iFileName );
    IObject topObj( archive, kTop );

    IPoints points( topObj, "simpleParticles" );
    IPointsSchema& pointsSchema = points.getSchema();

    index_t numSamps = pointsSchema.getNumSamples();
    std::cout << "\n\nReading points back in. Num frames: "
              << numSamps << std::endl;

    IV3fArrayProperty velProp( pointsSchema, "velocity" );
    IC3fArrayProperty rgbProp( pointsSchema, "Cs" );
    IFloatArrayProperty ageProp( pointsSchema, "age" );

    for ( index_t samp = 0; samp < numSamps; ++samp )
    {
        IPointsSchema::Sample psamp;
        pointsSchema.get( psamp, samp );

        Box3f bounds;
        bounds.makeEmpty();
        size_t numPoints = psamp.getPositions()->size();
        for ( size_t p = 0; p < numPoints; ++p )
        {
            bounds.extendBy( (*(psamp.getPositions()))[p] );
        }
        std::cout << "Sample: " << samp << ", numPoints: " << numPoints
                  << ", bounds: " << bounds.min
                  << " to " << bounds.max << std::endl;
    }
}
Exemple #8
0
bool intersectLine( const Box3f& box,
    const Vector3f& rayOrigin, const Vector3f& rayDirection,
    float& tNear, float& tFar )
{
    assert( box.isStandard() );
    assert( !box.isEmpty() );

    // Compute t to each face.
    Vector3f rcpDir = 1.0f / rayDirection;

    // Three "bottom" faces (min of the box).
    Vector3f tBottom = rcpDir * ( box.origin - rayOrigin );
    // three "top" faces (max of the box)
    Vector3f tTop = rcpDir * ( box.rightTopFront() - rayOrigin );

    // find the smallest and largest distances along each axis
    Vector3f tMin = libcgt::core::math::minimum( tBottom, tTop );
    Vector3f tMax = libcgt::core::math::maximum( tBottom, tTop );

    // tNear is the largest tMin
    tNear = libcgt::core::math::maximum( tMin );

    // tFar is the smallest tMax
    tFar = libcgt::core::math::minimum( tMax );

    return tFar > tNear;
}
Exemple #9
0
Imath::Box3f SceneProcedural::bound() const
{
	/// \todo I think we should be able to remove this exception handling in the future.
	/// Either when we do better error handling in ValuePlug computations, or when 
	/// the bug in IECoreGL that caused the crashes in SceneProceduralTest.testComputationErrors
	/// is fixed.
	try
	{
		ContextPtr timeContext = new Context( *m_context );
		Context::Scope scopedTimeContext( timeContext );
		
		/// \todo This doesn't take account of the unfortunate fact that our children may have differing
		/// numbers of segments than ourselves. To get an accurate bound we would need to know the different sample
		/// times the children may be using and evaluate a bound at those times as well. We don't want to visit
		/// the children to find the sample times out though, because that defeats the entire point of deferred loading.
		///
		/// Here are some possible approaches :
		///
		/// 1) Add a new attribute called boundSegments, which defines the number of segments used to calculate
		///    the bounding box. It would be the responsibility of the user to set this to an appropriate value
		///    at the parent levels, so that the parents calculate bounds appropriate for the children.
		///    This seems like a bit too much burden on the user.
		///
		/// 2) Add a global option called "maxSegments" - this will clamp the number of segments used on anything
		///    and will be set to 1 by default. The user will need to increase it to allow the leaf level attributes
		///    to take effect, and all bounding boxes everywhere will be calculated using that number of segments
		///    (actually I think it'll be that number of segments and all nondivisible smaller numbers). This should
		///    be accurate but potentially slower, because we'll be doing the extra work everywhere rather than only
		///    where needed. It still places a burden on the user (increasing the global clamp appropriately),
		///    but not quite such a bad one as they don't have to figure anything out and only have one number to set.
		///
		/// 3) Have the StandardOptions node secretly compute a global "maxSegments" behind the scenes. This would
		///    work as for 2) but remove the burden from the user. However, it would mean preventing any expressions
		///    or connections being used on the segments attributes, because they could be used to cheat the system.
		///    It could potentially be faster than 2) because it wouldn't have to do all nondivisible numbers - it
		///    could know exactly which numbers of segments were in existence. It still suffers from the
		///    "pay the price everywhere" problem.	
				
		std::set<float> times;
		motionTimes( ( m_options.deformationBlur && m_attributes.deformationBlur ) ? m_attributes.deformationBlurSegments : 0, times );
		motionTimes( ( m_options.transformBlur && m_attributes.transformBlur ) ? m_attributes.transformBlurSegments : 0, times );
				
		Box3f result;
		for( std::set<float>::const_iterator it = times.begin(), eIt = times.end(); it != eIt; it++ )
		{
			timeContext->setFrame( *it );
			Box3f b = m_scenePlug->boundPlug()->getValue();
			M44f t = m_scenePlug->transformPlug()->getValue();
			result.extendBy( transform( b, t ) );
		}
		
		return result;
	}
	catch( const std::exception &e )
	{
		IECore::msg( IECore::Msg::Error, "SceneProcedural::bound()", e.what() );
	}
	return Box3f();
}
Imath::Box3f StandardConnectionGadget::bound() const
{
	const_cast<StandardConnectionGadget *>( this )->setPositionsFromNodules();
	Box3f r;
	r.extendBy( m_srcPos );
	r.extendBy( m_dstPos );
	return r;
}
Exemple #11
0
const Box3f Box3f::getInvalid()
{
	Box3f retVal;

	retVal.setInvalid();

	return retVal;
}
Exemple #12
0
void GetRandPlane(Box3f &bb, Plane3f &plane)
{
    Point3f planeCenter = bb.Center();
    Point3f planeDir = Point3f(-0.5f+float(rand())/RAND_MAX,-0.5f+float(rand())/RAND_MAX,-0.5f+float(rand())/RAND_MAX);
    planeDir.Normalize();

    plane.Init(planeCenter+planeDir*0.3f*bb.Diag()*float(rand())/RAND_MAX,planeDir);
}
Exemple #13
0
bool carefulIntersectBoxRay( const Box3f& box,
    const Vector3f& rayOrigin, const Vector3f& rayDirection,
    float& t0, float& t1, int& t0Face, int& t1Face,
    float rayTMin, float rayTMax )
{
    assert( box.isStandard() );
    assert( !box.isEmpty() );

    t0 = rayTMin;
    t1 = rayTMax;
    t0Face = -1;
    t1Face = -1;

    // Compute t to each face.
    Vector3f rcpDir = 1.0f / rayDirection;

    Vector3f boxMax = box.rightTopFront();

    for( int i = 0; i < 3; ++i )
    {
        // Compute the intersection between the line and the slabs along the
        // i-th axis, parameterized as [tNear, tFar].
        float rcpDir = 1.0f / rayDirection[ i ];
        float tNear = rcpDir * ( box.origin[ i ] - rayOrigin[ i ] );
        float tFar = rcpDir * ( boxMax[ i ] - rayOrigin[ i ] );

        // Which face we're testing against.
        int nearFace = 2 * i;
        int farFace = 2 * i + 1;

        // Swap such that tNear < tFAr.
        if( tNear > tFar )
        {
            std::swap( tNear, tFar );
            std::swap( nearFace, farFace );
        }

        // Compute the set intersection between [tNear, tFar] and [t0, t1].
        if( tNear > t0 )
        {
            t0 = tNear;
            t0Face = nearFace;
        }
        if( tFar < t1 )
        {
            t1 = tFar;
            t1Face = farFace;
        }

        // Early abort if the range is empty.
        if( t0 > t1 )
        {
            return false;
        }
    }

    return true;
}
void IECoreArnold::RendererImplementation::procedural( IECore::Renderer::ProceduralPtr proc )
{
	Box3f bound = proc->bound();
	if( bound.isEmpty() )
	{
		return;
	}

	AtNode *procedural = AiNode( "procedural" );

	if( ExternalProcedural *externalProc = dynamic_cast<ExternalProcedural *>( proc.get() ) )
	{
		AiNodeSetStr( procedural, "dso", externalProc->fileName().c_str() );
		ParameterAlgo::setParameters( procedural, externalProc->parameters() );
		applyTransformToNode( procedural );
	}
	else
	{

		// we have to transform the bound, as we're not applying the current transform to the
		// procedural node, but instead applying absolute transforms to the shapes the procedural
		// generates.
		if( bound != Procedural::noBound )
		{
			Box3f transformedBound;
			for( size_t i = 0, e = m_transformStack.numSamples(); i < e; ++i )
			{
				transformedBound.extendBy( transform( bound, m_transformStack.sample( i ) ) );
			}
			bound = transformedBound;
		}

		AiNodeSetPtr( procedural, "funcptr", (void *)procLoader );

		ProceduralData *data = new ProceduralData;
		data->procedural = proc;
		data->renderer = new IECoreArnold::Renderer( new RendererImplementation( *this ) );

		AiNodeSetPtr( procedural, "userptr", data );
	}

	if( bound != Procedural::noBound )
	{
		AiNodeSetPnt( procedural, "min", bound.min.x, bound.min.y, bound.min.z );
		AiNodeSetPnt( procedural, "max", bound.max.x, bound.max.y, bound.max.z );
	}
	else
	{
		// No bound available - expand procedural immediately.
		AiNodeSetBool( procedural, "load_at_init", true );
	}

	// we call addNode() rather than addShape() as we don't want to apply transforms and
	// shaders and attributes to procedurals. if we do, they override the things we set
	// on the nodes generated by the procedurals, which is frankly useless.
	addNode( procedural );
}
Exemple #15
0
Box3f Quad::bounds() const
{
    Box3f result;
    result.grow(_base);
    result.grow(_base + _edge0);
    result.grow(_base + _edge1);
    result.grow(_base + _edge0 + _edge1);
    return result;
}
Exemple #16
0
Imath::Box3f Group::bound() const
{
	Box3f result;
	for( ChildContainer::const_iterator it=children().begin(); it!=children().end(); it++ )
	{
		result.extendBy( (*it)->bound() );
	}
	return transform( result, m_transform );
}
Exemple #17
0
// static
Box3f Box3f::united( const Box3f& b0, const Box3f& b1 )
{
    Vector3f unitedMin = libcgt::core::math::minimum(
        b0.leftBottomBack(), b1.leftBottomBack() );
    Vector3f unitedMax = libcgt::core::math::maximum(
        b0.rightTopFront(), b1.rightTopFront() );

    return{ unitedMin, unitedMax - unitedMin };
}
Exemple #18
0
void DotNodeGadget::doRender( const Style *style ) const
{
	Style::State state = getHighlighted() ? Style::HighlightedState : Style::NormalState;

	const Box3f b = bound();
	const V3f s = b.size();
	style->renderNodeFrame( Box2f( V2f( 0 ), V2f( 0 ) ), std::min( s.x, s.y ) / 2.0f, state, userColor() );

	NodeGadget::doRender( style );
}
Exemple #19
0
Imath::Box3f Seeds::computeBranchBound( const ScenePath &parentPath, const ScenePath &branchPath, const Gaffer::Context *context ) const
{
	Box3f b =  inPlug()->bound( parentPath );
	if( !b.isEmpty() )
	{
		// The PointsPrimitive we make has a default point width of 1,
		// so we must expand our bounding box to take that into account.
		b.min -= V3f( 0.5 );
		b.max += V3f( 0.5 );
	}
	return b;
}
Exemple #20
0
Box3f Cube::bounds() const
{
    Box3f box;
    for (int i = 0; i < 8; ++i) {
        box.grow(_pos + _rot*Vec3f(
            (i & 1 ? _scale.x() : -_scale.x()),
            (i & 2 ? _scale.y() : -_scale.y()),
            (i & 4 ? _scale.z() : -_scale.z())
        ));
    }
    return box;
}
Exemple #21
0
bool XfBox3f::intersect( const Vec3f& pt ) const
{
	if (xformInv[0][0] != std::numeric_limits<float>::max())
	{
		Vec3f p;
		xformInv.multVecMatrix(pt, p);
		return Box3f::intersect(p);
	}

	Box3f box = this->project();	// Degenerate; project and test:

	return box.intersect(pt);
}
Exemple #22
0
      VUTOctreeSubNodes::VUTOctreeSubNodes( const Box3f & box, const Vec3f & center, unsigned int maxIndicesPerOctel )
      {
        const Vec3f & lower = box.getLower();
        const Vec3f & upper = box.getUpper();

        nodes[0][0][0].init( Box3f( Vec3f( lower[0], lower[1], lower[2] ), Vec3f( center[0], center[1], center[2] ) ), maxIndicesPerOctel );
        nodes[0][0][1].init( Box3f( Vec3f( lower[0], lower[1], center[2] ), Vec3f( center[0], center[1], upper[2] ) ), maxIndicesPerOctel );
        nodes[0][1][0].init( Box3f( Vec3f( lower[0], center[1], lower[2] ), Vec3f( center[0], upper[1], center[2] ) ), maxIndicesPerOctel );
        nodes[0][1][1].init( Box3f( Vec3f( lower[0], center[1], center[2] ), Vec3f( center[0], upper[1], upper[2] ) ), maxIndicesPerOctel );
        nodes[1][0][0].init( Box3f( Vec3f( center[0], lower[1], lower[2] ), Vec3f( upper[0], center[1], center[2] ) ), maxIndicesPerOctel );
        nodes[1][0][1].init( Box3f( Vec3f( center[0], lower[1], center[2] ), Vec3f( upper[0], center[1], upper[2] ) ), maxIndicesPerOctel );
        nodes[1][1][0].init( Box3f( Vec3f( center[0], center[1], lower[2] ), Vec3f( upper[0], upper[1], center[2] ) ), maxIndicesPerOctel );
        nodes[1][1][1].init( Box3f( Vec3f( center[0], center[1], center[2] ), Vec3f( upper[0], upper[1], upper[2] ) ), maxIndicesPerOctel );
      }
Exemple #23
0
	void PlantExplosive::Enter()
	{
		// set position to base of construction
		Box3f obb = mMapGoal->GetWorldBounds();
		mExplosivePosition = obb.GetCenterBottom();
		mTargetPosition = mExplosivePosition;

		mAdjustedPosition = false;
		mGoalState = LAY_EXPLOSIVE;

		FINDSTATEIF( FollowPath, GetRootState(), Goto( this, Run, true ) );

		Tracker.InProgress = mMapGoal;
	}
Exemple #24
0
Imath::Box3f computeBounds(const float* vertices, size_t numVertices)
{
	using namespace Imath;
	Box3f bounds;
	bounds.makeEmpty();
	V3f vertex;
	for(size_t v=0; v < numVertices; ++v)
	{
		vertex.x = vertices[3 * v + 0];
		vertex.y = vertices[3 * v + 1];
		vertex.z = vertices[3 * v + 2];
		bounds.extendBy(vertex);
	}
	return bounds;
}
void StandardNodule::renderLabel( const Style *style ) const
{
	const NodeGadget *nodeGadget = ancestor<NodeGadget>();
	if( !nodeGadget )
	{
		return;
	}

	const std::string &label = plug()->getName().string();

	// we rotate the label based on the angle the connection exits the node at.
	V3f tangent = nodeGadget->noduleTangent( this );
	float theta = IECore::radiansToDegrees( atan2f( tangent.y, tangent.x ) );

	// but we don't want the text to be vertical, so we bend it away from the
	// vertical axis.
	if( ( theta > 0.0f && theta < 90.0f ) || ( theta < 0.0f && theta >= -90.0f ) )
	{
		theta = sign( theta ) * lerp( 0.0f, 45.0f, fabs( theta ) / 90.0f );
	}
	else
	{
		theta = sign( theta ) * lerp( 135.0f, 180.0f, (fabs( theta ) - 90.0f) / 90.0f );
	}

	// we also don't want the text to be upside down, so we correct the rotation
	// if that would be the case.
	Box3f labelBound = style->textBound( Style::LabelText, label );
	V2f anchor( labelBound.min.x - 1.0f, labelBound.center().y );

	if( theta > 90.0f || theta < -90.0f )
	{
		theta = theta - 180.0f;
		anchor.x = labelBound.max.x + 1.0f;
	}

	// now we can actually do the rendering.

	if( getHighlighted() )
	{
		glScalef( 1.2, 1.2, 1.2 );
	}

	glRotatef( theta, 0, 0, 1.0f );
	glTranslatef( -anchor.x, -anchor.y, 0.0f );

	style->renderText( Style::LabelText, label );
}
Exemple #26
0
 void VUTOctreeNode::init( const Box3f & bbox, unsigned int maxIndicesPerOctel )
 {
   m_box = bbox;
   m_center = bbox.getCenter();
   m_data = new VUTOctreeIndices( maxIndicesPerOctel );
   m_nodes = NULL;
 }
Exemple #27
0
void ImageView::preRender()
{
	if( m_framed )
	{
		return;
	}

	const Box3f b = m_imageGadget->bound();
	if( b.isEmpty() )
	{
		return;
	}

	viewportGadget()->frame( b );
	m_framed = true;
}
void CameraController::frame( const Imath::Box3f &box, const Imath::V3f &viewDirection, const Imath::V3f &upVector )
{
	// make a matrix to centre the camera on the box, with the appropriate view direction
	M44f cameraMatrix = rotationMatrixWithUpDir( V3f( 0, 0, -1 ), viewDirection, upVector );
	M44f translationMatrix;
	translationMatrix.translate( box.center() );
	cameraMatrix *= translationMatrix;

	// translate the camera back until the box is completely visible
	M44f inverseCameraMatrix = cameraMatrix.inverse();
	Box3f cBox = transform( box, inverseCameraMatrix );

	Box2f screenWindow = m_data->screenWindow->readable();
	if( m_data->projection->readable()=="perspective" )
	{
		// perspective. leave the field of view and screen window as is and translate
		// back till the box is wholly visible. this currently assumes the screen window
		// is centred about the camera axis.
		float z0 = cBox.size().x / screenWindow.size().x;
		float z1 = cBox.size().y / screenWindow.size().y;

		m_data->centreOfInterest = std::max( z0, z1 ) / tan( M_PI * m_data->fov->readable() / 360.0 ) + cBox.max.z +
			m_data->clippingPlanes->readable()[0];

		cameraMatrix.translate( V3f( 0.0f, 0.0f, m_data->centreOfInterest ) );
	}
	else
	{
		// orthographic. translate to front of box and set screen window
		// to frame the box, maintaining the aspect ratio of the screen window.
		m_data->centreOfInterest = cBox.max.z + m_data->clippingPlanes->readable()[0] + 0.1; // 0.1 is a fudge factor
		cameraMatrix.translate( V3f( 0.0f, 0.0f, m_data->centreOfInterest ) );

		float xScale = cBox.size().x / screenWindow.size().x;
		float yScale = cBox.size().y / screenWindow.size().y;
		float scale = std::max( xScale, yScale );

		V2f newSize = screenWindow.size() * scale;
		screenWindow.min.x = cBox.center().x - newSize.x / 2.0f;
		screenWindow.min.y = cBox.center().y - newSize.y / 2.0f;
		screenWindow.max.x = cBox.center().x + newSize.x / 2.0f;
		screenWindow.max.y = cBox.center().y + newSize.y / 2.0f;
	}

	m_data->transform->matrix = cameraMatrix;
	m_data->screenWindow->writable() = screenWindow;
}
Exemple #29
0
// static
bool Box3f::intersect( const Box3f& b0, const Box3f& b1, Box3f& intersection )
{
    Vector3f minimum = libcgt::core::math::maximum(
        b0.leftBottomBack(), b1.leftBottomBack() );
    Vector3f maximum = libcgt::core::math::minimum(
        b0.rightTopFront(), b1.rightTopFront() );

    if( minimum.x < maximum.x &&
        minimum.y < maximum.y &&
        minimum.z < maximum.z )
    {
        intersection.origin = minimum;
        intersection.size = maximum - minimum;
        return true;
    }
    return false;
}
static Box3fDataPtr bound3( const P *pData, const R *rData, float rMult, typename V::ConstPtr vData, float vMult )
{
	typedef typename P::ValueType::value_type Point;
	typedef typename V::ValueType::value_type Vector;
	typedef typename R::ValueType::value_type Radius;

	Box3f result;
	const typename P::ValueType &pVector = pData->readable();

	size_t vLength = 0;
	const Vector *v = 0;
	if( vData && vData->readable().size() )
	{
		vLength = vData->readable().size();
		v = &(vData->readable()[0]);
	}

	size_t rLength = 0;
	const Radius *r = 0;
	if( rData && rData->readable().size() )
	{
		rLength = rData->readable().size();
		r = &(rData->readable()[0]);
	}

	size_t i = 0;
	for( typename P::ValueType::const_iterator pIt = pVector.begin(); pIt!=pVector.end(); pIt++ )
	{
		Box3f b;
		b.extendBy( *pIt );
		if( v && i<vLength )
		{
			b.extendBy( *pIt + v[i] * vMult );
		}
		if( r && i<rLength )
		{
			Point rr( r[i] * rMult );
			b.min -= rr;
			b.max += rr;

		}
		result.extendBy( b );
		i++;
	}
	return new Box3fData( result );
}