+ /// class to just redirect triangles to the GroundCacheFillVisitor
+ class GroundCacheFill {
+ public:
+ void setGroundCacheFillVisitor(GroundCacheFillVisitor* gcfv)
+ { mGroundCacheFillVisitor = gcfv; }
+
+ void operator () (const osg::Vec3& v1, const osg::Vec3& v2,
+ const osg::Vec3& v3, bool)
+ { mGroundCacheFillVisitor->addTriangle(v1, v2, v3); }
+
+ void operator () (const osg::Vec3& v1, const osg::Vec3& v2, bool)
+ { mGroundCacheFillVisitor->addLine(v1, v2); }
+
+ private:
+ GroundCacheFillVisitor* mGroundCacheFillVisitor;
+ };
+
+
+ GroundCacheFillVisitor(FGGroundCache* groundCache,
+ const SGVec3d& down,
+ const SGVec3d& cacheReference,
+ double cacheRadius,
+ double wireCacheRadius) :
+ osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
+ mGroundCache(groundCache)
+ {
+ setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
+ mDown = down;
+ mLocalDown = down;
+ sphIsec = true;
+ mBackfaceCulling = false;
+ mCacheReference = cacheReference;
+ mLocalCacheReference = cacheReference;
+ mCacheRadius = cacheRadius;
+ mWireCacheRadius = wireCacheRadius;
+
+ mTriangleFunctor.setGroundCacheFillVisitor(this);
+
+ mGroundProperty.wire_id = -1;
+ mGroundProperty.vel = SGVec3d(0, 0, 0);
+ mGroundProperty.rot = SGVec3d(0, 0, 0);
+ mGroundProperty.pivot = SGVec3d(0, 0, 0);
+ }
+
+ void updateCullMode(osg::StateSet* stateSet)
+ {
+ if (!stateSet)
+ return;
+
+ osg::StateAttribute* stateAttribute;
+ stateAttribute = stateSet->getAttribute(osg::StateAttribute::CULLFACE);
+ if (!stateAttribute)
+ return;
+ osg::CullFace* cullFace = static_cast<osg::CullFace*>(stateAttribute);
+ mBackfaceCulling = cullFace->getMode() == osg::CullFace::BACK;
+ }
+
+ bool enterBoundingSphere(const osg::BoundingSphere& bs)
+ {
+ if (!bs.valid())
+ return false;
+
+ SGVec3d cntr(osg::Vec3d(bs.center())*mLocalToGlobal);
+ double rc = bs.radius() + mCacheRadius;
+ // Ok, this node might intersect the cache. Visit it in depth.
+ double centerDist2 = distSqr(mCacheReference, cntr);
+ if (centerDist2 < rc*rc) {
+ sphIsec = true;
+ } else {
+ // Check if the down direction touches the bounding sphere of the node
+ // if so, do at least croase agl computations.
+ // Ther other thing is that we must check if we are in range of
+ // cats or wires
+ double rw = bs.radius() + mWireCacheRadius;
+ if (rw*rw < centerDist2 &&
+ !fgdIsectSphereInfLine(cntr, bs.radius(), mCacheReference, mDown))
+ return false;
+ sphIsec = false;
+ }
+
+ return true;
+ }
+
+ bool enterNode(osg::Node& node)
+ {
+ if (!enterBoundingSphere(node.getBound()))
+ return false;
+
+ updateCullMode(node.getStateSet());
+
+ FGGroundCache::GroundProperty& gp = mGroundProperty;
+ // get some material information for use in the gear model
+ gp.material = globals->get_matlib()->findMaterial(&node);
+ if (gp.material) {
+ gp.type = gp.material->get_solid() ? FGInterface::Solid : FGInterface::Water;
+ return true;
+ }
+ gp.type = FGInterface::Unknown;
+ osg::Referenced* base = node.getUserData();
+ if (!base)
+ return true;
+ FGAICarrierHardware *ud =
+ dynamic_cast<FGAICarrierHardware*>(base);
+ if (!ud)
+ return true;
+