Box3f Mesh::computeBounds() const { Box3f bounds; for (int i = 0; i < _vertices.cols(); ++i) { bounds.expandBy(_vertices.col(i)); } return bounds; }
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; }
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; }
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); }
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; }
//-***************************************************************************** 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; } }
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; }
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; }
const Box3f Box3f::getInvalid() { Box3f retVal; retVal.setInvalid(); return retVal; }
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); }
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 ); }
Box3f Quad::bounds() const { Box3f result; result.grow(_base); result.grow(_base + _edge0); result.grow(_base + _edge1); result.grow(_base + _edge0 + _edge1); return result; }
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 ); }
// 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 }; }
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 ); }
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; }
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; }
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); }
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 ); }
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; }
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 ); }
void VUTOctreeNode::init( const Box3f & bbox, unsigned int maxIndicesPerOctel ) { m_box = bbox; m_center = bbox.getCenter(); m_data = new VUTOctreeIndices( maxIndicesPerOctel ); m_nodes = NULL; }
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; }
// 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 ); }