/* Test if a scene node intersected a portal during the last time delta
* (from last frame time to current frame time). This function checks
* if the node "crossed over" the portal also.
*/
public PortalIntersectResult intersects(PCZSceneNode pczsn)
{
// Only check if portal is open
if (this.mOpen)
{
if (pczsn == this.mNode)
{
// ignore the scene node if it is the node the portal is associated with
return(PortalIntersectResult.NO_INTERSECT);
}
// most complicated case - if the portal is a quad:
if (this.mType == PORTAL_TYPE.PORTAL_TYPE_QUAD)
{
// the node is modeled as a line segment (prevPostion to currentPosition)
// intersection test is then between the capsule and the line segment.
var nodeSegment = new Segment();
nodeSegment.Set(pczsn.PreviousPosition, pczsn.DerivedPosition);
// we model the portal as a line swept sphere (mPrevDerivedCP to mDerivedCP).
var portalCapsule = new Capsule();
portalCapsule.Set(this.mPrevDerivedCP, this.mDerivedCP, this.mRadius);
if (portalCapsule.Intersects(nodeSegment))
{
// the portal intersected the node at some time from last frame to this frame.
// Now check if node "crossed" the portal
// a crossing occurs if the "side" of the final position of the node compared
// to the final position of the portal is negative AND the initial position
// of the node compared to the initial position of the portal is non-negative
if (this.mDerivedPlane.GetSide(pczsn.DerivedPosition) == PlaneSide.Negative &&
this.mPrevDerivedPlane.GetSide(pczsn.DerivedPosition) != PlaneSide.Negative)
{
// safety check - make sure the node has at least one dimension which is
// small enough to fit through the portal! (avoid the "elephant fitting
// through a mouse hole" case)
Vector3 nodeHalfVector = pczsn.WorldAABB.HalfSize;
var portalBox = new Vector3(this.mRadius, this.mRadius, this.mRadius);
portalBox.Floor(nodeHalfVector);
if (portalBox.x < this.mRadius)
{
// crossing occurred!
return(PortalIntersectResult.INTERSECT_CROSS);
}
}
}
// there was no crossing of the portal by the node, but it might be touching
// the portal. We check for this by checking the bounding box of the node vs.
// the sphere of the portal
if (this.mDerivedSphere.Intersects(pczsn.WorldAABB) &&
this.mDerivedPlane.GetSide(pczsn.WorldAABB) == PlaneSide.Both)
{
// intersection but no crossing
// note this means that the node is CURRENTLY touching the portal.
if (this.mDerivedPlane.GetSide(pczsn.DerivedPosition) != PlaneSide.Negative)
{
// the node is on the positive (front) or exactly on the CP of the portal
return(PortalIntersectResult.INTERSECT_NO_CROSS);
}
else
{
// the node is on the negative (back) side of the portal - it might be in the wrong zone!
return(PortalIntersectResult.INTERSECT_BACK_NO_CROSS);
}
}
// no intersection CURRENTLY. (there might have been an intersection
// during the time between last frame and this frame, but it wasn't a portal
// crossing, and it isn't touching anymore, so it doesn't matter.
return(PortalIntersectResult.NO_INTERSECT);
}
else if (this.mType == PORTAL_TYPE.PORTAL_TYPE_AABB)
{
// for aabb's we check if the center point went from being inside to being outside
// the aabb (or vice versa) for crossing.
var aabb = new AxisAlignedBox(this.mDerivedCorners[0], this.mDerivedCorners[1]);
//bool previousInside = aabb.contains(pczsn->getPrevPosition());
bool currentInside = aabb.Contains(pczsn.DerivedPosition);
if (this.mDirection == Vector3.UnitZ)
{
// portal norm is "outward" pointing, look for going from outside to inside
//if (previousInside == false &&
if (currentInside == true)
{
return(PortalIntersectResult.INTERSECT_CROSS);
}
}
else
{
// portal norm is "inward" pointing, look for going from inside to outside
//if (previousInside == true &&
if (currentInside == false)
{
return(PortalIntersectResult.INTERSECT_CROSS);
}
}
// doesn't cross, but might be touching. This is a little tricky because we only
// care if the node aab is NOT fully contained in the portal aabb because we consider
// the surface of the portal aabb the actual 'portal'. First, check to see if the
// aab of the node intersects the aabb portal
if (aabb.Intersects(pczsn.WorldAABB))
{
// now check if the intersection between the two is not the same as the
// full node aabb, if so, then this means that the node is not fully "contained"
// which is what we are looking for.
AxisAlignedBox overlap = aabb.Intersection(pczsn.WorldAABB);
if (overlap != pczsn.WorldAABB)
{
return(PortalIntersectResult.INTERSECT_NO_CROSS);
}
}
return(PortalIntersectResult.NO_INTERSECT);
}
else
{
// for spheres we check if the center point went from being inside to being outside
// the sphere surface (or vice versa) for crossing.
//Real previousDistance2 = mPrevDerivedCP.squaredDistance(pczsn->getPrevPosition());
Real currentDistance2 = this.mDerivedCP.DistanceSquared(pczsn.DerivedPosition);
Real mRadius2 = this.mRadius * this.mRadius;
if (this.mDirection == Vector3.UnitZ)
{
// portal norm is "outward" pointing, look for going from outside to inside
//if (previousDistance2 >= mRadius2 &&
if (currentDistance2 < mRadius2)
{
return(PortalIntersectResult.INTERSECT_CROSS);
}
}
else
{
// portal norm is "inward" pointing, look for going from inside to outside
//if (previousDistance2 < mRadius2 &&
if (currentDistance2 >= mRadius2)
{
return(PortalIntersectResult.INTERSECT_CROSS);
}
}
// no crossing, but might be touching - check distance
if (System.Math.Sqrt(System.Math.Abs(mRadius2 - currentDistance2)) <= this.mRadius)
{
return(PortalIntersectResult.INTERSECT_NO_CROSS);
}
return(PortalIntersectResult.NO_INTERSECT);
}
}
return(PortalIntersectResult.NO_INTERSECT);
}