📄 plane.cpp
字号:
//===========================================================================//
// File: plane.cc //
// Contents: Implementation details for the plane class //
//---------------------------------------------------------------------------//
// Copyright (C) Microsoft Corporation. All rights reserved. //
//===========================================================================//
#include "StuffHeaders.hpp"
//
//#############################################################################
//#############################################################################
//
void
Plane::BuildPlane(
const Point3D& p0,
const Point3D& p1,
const Point3D& p2
)
{
Vector3D v1,v2;
v1.Subtract(p1, p0);
v2.Subtract(p2, p1);
Vector3D axis;
axis.Cross(v1, v2);
Verify(!Small_Enough(axis.GetLength()));
normal = axis;
offset = normal * p0;
#if defined(_ARMOR)
Scalar offset2 = normal * p1;
Scalar offset3 = normal * p2;
//
//----------------------------------------------------------------
// occasionaly the offset becomes large and the triangle is small
// this way we still maintain proof up to 1e-4 of the offset value
//----------------------------------------------------------------
//
Verify(Close_Enough(
offset,
offset2,
Fabs(offset+offset2) > 200.0f
? SMALL*Fabs(offset+offset2)/200.0f
: SMALL
));
Verify(Close_Enough(
offset,
offset3,
Fabs(offset+offset3) > 200.0f
? SMALL*Fabs(offset+offset3)/200.0f
: SMALL
));
#endif
}
//
//#############################################################################
//#############################################################################
//
Plane&
Plane::Multiply(
const Plane &p,
const LinearMatrix4D &m
)
{
Check_Pointer(this);
Check_Object(&p);
Check_Object(&m);
Verify(this != &p);
normal.x = p.normal.x*m(0,0) + p.normal.y*m(1,0) + p.normal.z*m(2,0);
normal.y = p.normal.x*m(0,1) + p.normal.y*m(1,1) + p.normal.z*m(2,1);
normal.z = p.normal.x*m(0,2) + p.normal.y*m(1,2) + p.normal.z*m(2,2);
offset =
normal.x*m(3,0) + normal.y*m(3,1) + normal.z*m(3,2) + p.offset;
return *this;
}
//
//#############################################################################
//#############################################################################
//
Scalar
Plane::GetDistanceTo(const Sphere& sphere) const
{
Check_Object(this);
Check_Object(&sphere);
//
//-----------------------------------------------------------------------
// Find out how far the centerpoint of the sphere is from us, then adjust
// so that 0.0 means we are intersecting the sphere
//-----------------------------------------------------------------------
//
Scalar distance = GetDistanceTo(sphere.center);
if (distance > sphere.radius)
return distance - sphere.radius;
else if (distance < -sphere.radius)
return distance + sphere.radius;
return 0.0f;
}
//
//#############################################################################
//#############################################################################
//
Scalar
Plane::GetDistanceTo(const OBB& box) const
{
Check_Object(this);
Check_Object(&box);
//
//-------------------------------------------------
// Rotate the plane into the local space of the box
//-------------------------------------------------
//
Plane local_plane;
LinearMatrix4D parent_to_local;
parent_to_local.Invert(box.localToParent);
local_plane.Multiply(*this, parent_to_local);
Point3D inside_extents(box.axisExtents);
Point3D outside_extents(box.axisExtents);
//
//---------------------------------------------------------------------
// Look at the resulting vector to find out which corners of the box we
// should be testing
//---------------------------------------------------------------------
//
if (local_plane.normal.x > 0.0f)
inside_extents.x = -inside_extents.x;
else
outside_extents.x = -outside_extents.x;
if (local_plane.normal.y > 0.0f)
inside_extents.y = -inside_extents.y;
else
outside_extents.y = -outside_extents.y;
if (local_plane.normal.z > 0.0f)
inside_extents.z = -inside_extents.z;
else
outside_extents.z = -outside_extents.z;
//
//---------------------------
// Test against the plane now
//---------------------------
//
Scalar distance = local_plane.GetDistanceTo(outside_extents);
if (distance < 0.0f)
return distance;
distance = local_plane.GetDistanceTo(inside_extents);
if (distance > 0.0f)
return distance;
return 0.0f;
}
//
//#############################################################################
//#############################################################################
//
bool
Plane::ContainsSomeOf(
const Sphere &sphere,
Scalar thickness
) const
{
return normal*sphere.center - offset <= sphere.radius - thickness;
}
//
//#############################################################################
//#############################################################################
//
bool
Plane::ContainsAllOf(
const Sphere &sphere,
Scalar thickness
) const
{
return offset - normal*sphere.center >= sphere.radius + thickness;
}
//
//#############################################################################
//#############################################################################
//
bool
Plane::ContainsSomeOf(
const ExtentBox &box,
Scalar thickness
) const
{
Check_Object(this);
Check_Object(&box);
Point3D test;
test.x = (normal.x > 0.0f) ? box.minX : box.maxX;
test.y = (normal.y > 0.0f) ? box.minY : box.maxY;
test.z = (normal.z > 0.0f) ? box.minZ : box.maxZ;
return normal * test < offset - thickness;
}
//
//#############################################################################
//#############################################################################
//
bool
Plane::ContainsAllOf(
const ExtentBox &box,
Scalar thickness
) const
{
Check_Object(this);
Check_Object(&box);
Point3D test;
test.x = (normal.x < 0.0f) ? box.minX : box.maxX;
test.y = (normal.y < 0.0f) ? box.minY : box.maxY;
test.z = (normal.z < 0.0f) ? box.minZ : box.maxZ;
return normal * test <= offset + thickness;
}
//
//#############################################################################
//#############################################################################
//
bool
Plane::Intersects(
const Sphere &sphere,
Scalar thickness
) const
{
Scalar dist = normal*sphere.center - offset;
return Abs(dist) <= sphere.radius + thickness;
}
//
//#############################################################################
//#############################################################################
//
bool
Plane::Intersects(
const ExtentBox &box,
Scalar thickness
) const
{
if (!ContainsSomeOf(box, thickness))
{
return false;
}
STOP(("What is this????"));
Plane inverse(-normal.x, -normal.y, -normal.z, -offset);
return false;
// return inverse.ContainsSomeOf(box);
}
//
//#############################################################################
//#############################################################################
//
#if !defined(Spew)
void
Spew(
const char* group,
const Plane& plane
)
{
Check_Object(&plane);
SPEW((group, "\n\tPlane Normal: +"));
Spew(group, plane.normal);
SPEW((group, "\tOffset: %f+", plane.offset));
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
Plane::ComputeBestDividingPlane(DynamicArrayOf<Point3D> &points)
{
Check_Object(&points);
//
//-----------------
// Compute the sums
//-----------------
//
unsigned count = points.GetLength();
Verify(count > 1);
Point3D sum = Point3D::Identity;
Scalar xx = 0.0f;
Scalar xy = 0.0f;
Scalar xz = 0.0f;
Scalar yy = 0.0f;
Scalar yz = 0.0f;
Scalar zz = 0.0f;
unsigned i;
for (i=0; i<count; i++)
{
sum += points[i];
xx += points[i].x*points[i].x;
xy += points[i].x*points[i].y;
xz += points[i].x*points[i].z;
yy += points[i].y*points[i].y;
yz += points[i].y*points[i].z;
zz += points[i].z*points[i].z;
}
//
//--------------------------------------
// Compute the least squares differences
//--------------------------------------
//
Scalar t = 1.0f / static_cast<Scalar>(count);
xx -= t*sum.x*sum.x;
xy -= t*sum.x*sum.y;
xz -= t*sum.x*sum.z;
yy -= t*sum.y*sum.y;
yz -= t*sum.y*sum.z;
zz -= t*sum.z*sum.z;
//
//------------------------------------------------------------------
// Find the largest axis component, and use that to orient the plane
//------------------------------------------------------------------
//
int axis;
if (xx > yy)
axis = (xx > zz) ? X_Axis : Z_Axis;
else
axis = (yy > zz) ? Y_Axis : Z_Axis;
Vector3D direction;
switch (axis)
{
case X_Axis:
if (xx < SMALL)
return false;
direction.x = 1.0f;
direction.y = xy / xx;
direction.z = xz / xx;
break;
case Y_Axis:
if (yy < SMALL)
return false;
Verify(yy > SMALL);
direction.x = xy / yy;
direction.y = 1.0f;
direction.z = yz / yy;
break;
case Z_Axis:
if (zz < SMALL)
return false;
direction.x = xz / zz;
direction.y = yz / zz;
direction.z = 1.0f;
break;
default:
direction = Vector3D::Identity;
STOP(("Bad switch"));
}
//
//-----------------------------------------------------------------------
// The dividing plane will coincide with the mean point and have a normal
// parallel to the variance vector
//-----------------------------------------------------------------------
//
normal = direction;
sum *= t;
offset = normal * sum;
Check_Object(this);
//
//-----------------------------------------------------------------------
// Now make sure that a coincident set didn't get through due to rounding
// errors
//-----------------------------------------------------------------------
//
for (i=0; i<count; i++)
{
if (points[i] != sum)
return true;
}
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -