1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include "[Math/MathFunc.h]"19 #include "[Math/Polynomial.h]"20 #include "[Geometry/AABB.h]"21 #include "[Geometry/Circle.h]"22 #include "[Geometry/Plane.h]"23 #include "[Geometry/Line.h]"24 #include "[Geometry/OBB.h]"25 #include "[Geometry/Polygon.h]"26 #include "[Geometry/Polyhedron.h]"27 #include "[Geometry/Ray.h]"28 #include "[Geometry/Capsule.h]"29 #include "[Geometry/Sphere.h]"30 #include "[Geometry/Triangle.h]"31 #include "[Geometry/LineSegment.h]"32 #include "[Math/float3x3.h]"33 #include "[Math/float3x4.h]"34 #include "[Math/float4.h]"35 #include "[Math/Quat.h]"36 #include "[Geometry/Frustum.h]"37 38 [MATH_BEGIN_NAMESPACE]39 40 [Plane::Plane](const [float3] &normal_, float d_)41 :normal(normal_), d(d_)42 {43 [assume](normal.IsNormalized());44 }45 46 [Plane::Plane](const [float3] &v1, const [float3] &v2, const [float3] &v3)47 {48 [Set](v1, v2, v3);49 }50 51 [Plane::Plane](const [float3] &point, const [float3] &normal_)52 {53 [Set](point, normal_);54 }55 56 [Plane::Plane](const [Ray] &ray, const [float3] &normal)57 {58 [float3] perpNormal = normal - normal.[ProjectToNorm](ray.[dir]);59 [Set](ray.[pos], perpNormal.[Normalized]());60 }61 62 [Plane::Plane](const [Line] &line, const [float3] &normal)63 {64 [float3] perpNormal = normal - normal.[ProjectToNorm](line.[dir]);65 [Set](line.[pos], perpNormal.[Normalized]());66 }67 68 [Plane::Plane](const [LineSegment] &lineSegment, const [float3] &normal)69 {70 [float3] perpNormal = normal - normal.[ProjectTo](lineSegment.[b] - lineSegment.[a]);71 [Set](lineSegment.[a], perpNormal.[Normalized]());72 }73 74 void [Plane::Set](const [float3] &v1, const [float3] &v2, const [float3] &v3)75 {76 normal = (v2-v1).[Cross](v3-v1);77 [assume](!normal.[IsZero]());78 normal.[Normalize]();79 [d] = [Dot](v1, normal);80 81 [assume]([EqualAbs]([SignedDistance](v1), 0.f));82 [assume]([EqualAbs]([SignedDistance](v2), 0.f));83 [assume]([EqualAbs]([SignedDistance](v3), 0.f));84 [assume]([EqualAbs]([SignedDistance](v3 + normal), 1.f));85 }86 87 void [Plane::Set](const [float3] &point, const [float3] &normal_)88 {89 normal = normal_;90 [assume](normal.[IsNormalized]());91 [d] = [Dot](point, normal);92 93 [assume]([EqualAbs]([SignedDistance](point), 0.f));94 [assume]([EqualAbs]([SignedDistance](point + normal_), 1.f));95 }96 97 void [Plane::ReverseNormal]()98 {99 normal = -[normal];100 d = -[d];101 }102 103 [float3] [Plane::PointOnPlane]() const104 {105 return normal * [d];106 }107 108 void [Plane::Transform](const [float3x3] &transform)109 {110 [float3x3] it = transform.[InverseTransposed](); 111 normal = it * [normal];112 }113 114 115 void [Plane::Transform](const [float3x4] &transform)116 {117 118 [float3x3] r = transform.[Float3x3Part]();119 bool success = r.[Inverse](); 120 [assume](success);121 d = d + [Dot](normal, r * transform.[TranslatePart]());122 normal = normal * r;123 }124 125 void [Plane::Transform](const [float4x4] &transform)126 {127 [assume](transform.[Row](3).[Equals]([float4](0,0,0,1)));128 [Transform](transform.[Float3x4Part]());129 }130 131 void [Plane::Transform](const [Quat] &transform)132 {133 [float3x3] r = transform.[ToFloat3x3]();134 [Transform](r);135 }136 137 bool [Plane::IsInPositiveDirection](const [float3] &directionVector) const138 {139 return normal.[Dot](directionVector) >= 0.f;140 }141 142 bool [Plane::IsOnPositiveSide](const [float3] &point) const143 {144 return [SignedDistance](point) >= 0.f;145 }146 147 int [Plane::ExamineSide](const [Triangle] &triangle) const148 {149 float a = [SignedDistance](triangle.[a]);150 float b = [SignedDistance](triangle.[b]);151 float c = [SignedDistance](triangle.[c]);152 const float epsilon = 1[e]-4f; 153 if (a >= -epsilon && b >= -epsilon && c >= -epsilon)154 return 1;155 if (a <= epsilon && b <= epsilon && c <= epsilon)156 return -1;157 return 0;158 }159 160 bool [Plane::AreOnSameSide](const [float3] &p1, const [float3] &p2) const161 {162 return [SignedDistance](p1) * [SignedDistance](p2) >= 0.f;163 }164 165 float [Plane::Distance](const [float3] &point) const166 {167 return [Abs]([SignedDistance](point));168 }169 170 float [Plane::Distance](const [LineSegment] &lineSegment) const171 {172 return lineSegment.[Distance](*this);173 }174 175 float [Plane::Distance](const [Sphere] &sphere) const176 {177 return [Max](0.f, [Distance](sphere.[pos]) - sphere.[r]);178 }179 180 float [Plane::Distance](const [Capsule] &capsule) const181 {182 return [Max](0.f, [Distance](capsule.[l]) - capsule.[r]);183 }184 185 float [Plane::SignedDistance](const [float3] &point) const186 {187 return normal.[Dot](point) - [d];188 }189 190 [float3x4] [Plane::OrthoProjection]() const191 {192 return [float3x4::OrthographicProjection](*this);193 }194 195 [float3x4] [Plane::ObliqueProjection](const [float3] &obliqueProjectionDir) const196 {197 [assume](false && "Not implemented!"); 198 return [float3x4]();199 }200 201 [float3x4] [Plane::MirrorMatrix]() const202 {203 return [float3x4::Mirror](*this);204 }205 206 [float3] [Plane::Mirror](const [float3] &point) const207 {208 [assume](normal.[IsNormalized]());209 [float3] reflected = point - 2.f * ([Dot](point, normal) + [d]) * normal;210 [assume](reflected.Equals([MirrorMatrix]().MulPos(point)));211 return reflected;212 }213 214 [float3] [Plane::Refract](const [float3] &vec, float negativeSideRefractionIndex, float positiveSideRefractionIndex) const215 {216 return [float3](vec).[Refract](normal, negativeSideRefractionIndex, positiveSideRefractionIndex);217 }218 219 [float3] [Plane::Project](const [float3] &point) const220 {221 [float3] projected = point - ([Dot](normal, point) - [d]) * normal;222 [assume](projected.[Equals]([OrthoProjection]().MulPos(point)));223 return projected;224 }225 226 [LineSegment] [Plane::Project](const [LineSegment] &lineSegment) const227 {228 return [LineSegment]([Project](lineSegment.[a]), [Project](lineSegment.[b]));229 }230 231 [Line] [Plane::Project](const [Line] &line, bool *nonDegenerate) const232 {233 [Line] l;234 l.[pos] = [Project](line.[pos]);235 l.[dir] = l.[dir] - l.[dir].[ProjectToNorm](normal);236 float len = l.[dir].[Normalize]();237 if (nonDegenerate)238 *nonDegenerate = (len > 0.f);239 return l;240 }241 242 [Ray] [Plane::Project](const [Ray] &ray, bool *nonDegenerate) const243 {244 [Ray] r;245 r.[pos] = [Project](ray.[pos]);246 r.[dir] = r.[dir] - r.[dir].[ProjectToNorm](normal);247 float len = r.[dir].[Normalize]();248 if (nonDegenerate)249 *nonDegenerate = (len > 0.f);250 return r;251 }252 253 [Triangle] [Plane::Project](const [Triangle] &triangle) const254 {255 [Triangle] t;256 t.[a] = [Project](triangle.[a]);257 t.[b] = [Project](triangle.[b]);258 t.[c] = [Project](triangle.[c]);259 return t;260 }261 262 [Polygon] [Plane::Project](const [Polygon] &polygon) const263 {264 [Polygon] p;265 for(size_t i = 0; i < polygon.[p].size(); ++i)266 p.[p].push_back([Project](polygon.[p][i]));267 268 return p;269 }270 271 [float3] [Plane::ClosestPoint](const [Ray] &ray) const272 {273 274 float [d];275 if (ray.[Intersects](*this, &d))276 return ray.[GetPoint](d);277 else278 return [Project](ray.[pos]);279 }280 281 [float3] [Plane::ClosestPoint](const [LineSegment] &lineSegment) const282 {283 284 float [d];285 if (lineSegment.[Intersects](*this, &d))286 return lineSegment.[GetPoint](d);287 else288 if ([Distance](lineSegment.[a]) < [Distance](lineSegment.[b]))289 return [Project](lineSegment.[a]);290 else291 return [Project](lineSegment.[b]);292 }293 294 [float3] [Plane::ObliqueProject](const [float3] &point, const [float3] &obliqueProjectionDir) const295 {296 [assume](false && "Not implemented!"); 297 return [float3]();298 }299 300 bool [Plane::Contains](const [float3] &point, float distanceThreshold) const301 {302 return [Distance](point) <= distanceThreshold;303 }304 305 bool [Plane::Contains](const [Line] &line, float epsilon) const306 {307 return [Contains](line.[pos]) && line.[dir].[IsPerpendicular](normal, epsilon);308 }309 310 bool [Plane::Contains](const [Ray] &ray, float epsilon) const311 {312 return [Contains](ray.[pos]) && ray.[dir].[IsPerpendicular](normal, epsilon);313 }314 315 bool [Plane::Contains](const [LineSegment] &lineSegment, float epsilon) const316 {317 return [Contains](lineSegment.[a], epsilon) && [Contains](lineSegment.[b], epsilon);318 }319 320 bool [Plane::Contains](const [Triangle] &triangle, float epsilon) const321 {322 return [Contains](triangle.[a], epsilon) && [Contains](triangle.[b], epsilon) && [Contains](triangle.[c], epsilon);323 }324 325 bool [Plane::Contains](const [Circle] &circle, float epsilon) const326 {327 return [Contains](circle.[pos], epsilon) && ([EqualAbs]([Abs]([Dot](normal, circle.[normal])), 1.f) || circle.[r] <= epsilon);328 }329 330 bool [Plane::Contains](const [Polygon] &polygon, float epsilon) const331 {332 switch(polygon.[NumVertices]())333 {334 case 0: [assume](false && "Plane::Contains(Polygon) called with a degenerate polygon of 0 vertices!"); return false;335 case 1: return [Contains](polygon.[Vertex](0), epsilon);336 case 2: return [Contains](polygon.[Vertex](0), epsilon) && [Contains](polygon.[Vertex](1), epsilon);337 default:338 return [SetEquals](polygon.[PlaneCCW](), epsilon);339 }340 }341 342 bool [Plane::SetEquals](const [Plane] &plane, float epsilon) const343 {344 return (normal.[Equals](plane.[normal]) && [EqualAbs](d, plane.[d], epsilon)) ||345 (normal.[Equals](-plane.[normal]) && [EqualAbs](-d, plane.[d], epsilon));346 }347 348 bool [Plane::Equals](const [Plane] &other, float epsilon) const349 {350 return [IsParallel](other, epsilon) && [EqualAbs](d, other.[d], epsilon);351 }352 353 bool [Plane::Intersects](const [Plane] &plane, [Line] *outLine) const354 {355 [float3] perp = [Cross](normal, plane.[normal]);356 357 [float3x3] m;358 m.[SetRow](0, normal);359 m.[SetRow](1, plane.[normal]);360 m.[SetRow](2, perp); 361 bool success = m.[Inverse]();362 if (!success) 363 {364 if ([EqualAbs](d, plane.[d])) 365 {366 if (outLine)367 *outLine = [Line](plane.[PointOnPlane](), plane.[normal].[Perpendicular]());368 return true;369 }370 else371 return false;372 }373 if (outLine)374 *outLine = [Line](m * [float3](d, plane.[d], 0.f), perp.[Normalized]());375 return true;376 }377 378 bool [Plane::Intersects](const [Plane] &plane, const [Plane] &plane2, [Line] *outLine, [float3] *outPoint) const379 {380 [Line] dummy;381 if (!outLine)382 outLine = &dummy;383 384 385 if (this->[IsParallel](plane) || this->[IsParallel](plane2))386 {387 if ([EqualAbs](d, plane.[d]) || [EqualAbs](d, plane2.[d]))388 {389 bool intersect = plane.[Intersects](plane2, outLine);390 if (intersect && outPoint)391 *outPoint = outLine->[GetPoint](0);392 return intersect;393 }394 else395 return false;396 }397 if (plane.[IsParallel](plane2))398 {399 if ([EqualAbs](plane.[d], plane2.[d]))400 {401 bool intersect = this->[Intersects](plane, outLine);402 if (intersect && outPoint)403 *outPoint = outLine->[GetPoint](0);404 return intersect;405 }406 else407 return false;408 }409 410 411 [float3x3] m;412 m.[SetRow](0, normal);413 m.[SetRow](1, plane.[normal]);414 m.[SetRow](2, plane2.[normal]);415 bool success = m.[Inverse]();416 if (!success)417 return false;418 if (outPoint)419 *outPoint = m * [float3](d, plane.[d], plane2.[d]);420 return true;421 }422 423 bool [Plane::Intersects](const [Polygon] &polygon) const424 {425 return polygon.[Intersects](*this);426 }427 428 429 430 431 432 433 434 435 436 bool [IntersectLinePlane](const [float3] &ptOnPlane, const [float3] &planeNormal, const [float3] &lineStart, const [float3] &lineDir, float *t)437 {438 float denom = [Dot](lineDir, planeNormal);439 if ([EqualAbs](denom, 0.f))440 return false; 441 if (t)442 *t = [Dot](ptOnPlane - lineStart, planeNormal);443 return true;444 }445 446 bool [Plane::Intersects](const [Ray] &ray, float *d) const447 {448 float t;449 bool success = [IntersectLinePlane]([PointOnPlane](), normal, ray.[pos], ray.[dir], &t);450 if (d)451 *d = t;452 return success && t >= 0.f;453 }454 455 bool [Plane::Intersects](const [Line] &line, float *d) const456 {457 return [IntersectLinePlane]([PointOnPlane](), normal, line.[pos], line.[dir], d);458 }459 460 bool [Plane::Intersects](const [LineSegment] &lineSegment, float *d) const461 {462 float t;463 bool success = [IntersectLinePlane]([PointOnPlane](), normal, lineSegment.[a], lineSegment.[Dir](), &t);464 const float lineSegmentLength = lineSegment.[Length]();465 if (d)466 *d = t / lineSegmentLength;467 return success && t >= 0.f && t <= lineSegmentLength;468 }469 470 bool [Plane::Intersects](const [Sphere] &sphere) const471 {472 return [Distance](sphere.[pos]) <= sphere.[r];473 }474 475 bool [Plane::Intersects](const [Capsule] &capsule) const476 {477 return capsule.[Intersects](*this);478 }479 480 481 bool [Plane::Intersects](const [AABB] &aabb) const482 {483 [float3] c = aabb.[CenterPoint]();484 [float3] [e] = aabb.[HalfDiagonal]();485 486 487 float r = e[0]*[Abs](normal[0]) + e[1]*[Abs](normal[1]) + e[2]*[Abs](normal[2]);488 489 float s = [Dot](normal, c) - [d];490 return [Abs](s) <= r;491 }492 493 bool [Plane::Intersects](const [OBB] &obb) const494 {495 return obb.[Intersects](*this);496 }497 498 bool [Plane::Intersects](const [Triangle] &triangle) const499 {500 float a = [SignedDistance](triangle.[a]);501 float b = [SignedDistance](triangle.[b]);502 float c = [SignedDistance](triangle.[c]);503 return (a*b <= 0.f || a*c <= 0.f);504 }505 506 bool [Plane::Intersects](const [Frustum] &frustum) const507 {508 bool sign = [IsOnPositiveSide](frustum.[CornerPoint](0));509 for(int i = 1; i < 8; ++i)510 if (sign != [IsOnPositiveSide](frustum.[CornerPoint](i)))511 return true;512 return false;513 }514 515 bool [Plane::Intersects](const [Polyhedron] &polyhedron) const516 {517 if (polyhedron.[NumVertices]() == 0)518 return false;519 bool sign = [IsOnPositiveSide](polyhedron.[Vertex](0));520 for(int i = 1; i < polyhedron.[NumVertices](); ++i)521 if (sign != [IsOnPositiveSide](polyhedron.[Vertex](i)))522 return true;523 return false;524 }525 526 int [Plane::Intersects](const [Circle] &circle, [float3] *pt1, [float3] *pt2) const527 {528 [Line] line;529 bool planeIntersects = [Intersects](circle.[ContainingPlane](), &line);530 if (!planeIntersects)531 return false;532 533 534 line.[pos] -= circle.[pos];535 536 float a = 1.f;537 float b = 2.f * [Dot](line.[pos], line.[dir]);538 float c = line.[pos].[LengthSq]() - circle.[r] * circle.[r];539 float r1, r2;540 int numRoots = [Polynomial::SolveQuadratic](a, b, c, r1, r2);541 if (numRoots >= 1 && pt1)542 *pt1 = circle.[pos] + line.[GetPoint](r1);543 if (numRoots >= 2 && pt2)544 *pt2 = circle.[pos] + line.[GetPoint](r2);545 return numRoots;546 }547 548 int [Plane::Intersects](const [Circle] &circle) const549 {550 return [Intersects](circle, 0, 0);551 }552 553 bool [Plane::Clip]([float3] &a, [float3] &b) const554 {555 float t;556 bool intersects = [IntersectLinePlane]([PointOnPlane](), normal, a, b-a, &t);557 if (!intersects || t <= 0.f || t >= 1.f)558 {559 if ([SignedDistance](a) <= 0.f)560 return false; 561 else562 return true; 563 }564 [float3] pt = a + (b-a) * t; 565 566 if ([IsOnPositiveSide](a))567 b = pt;568 else569 a = pt;570 571 return true;572 }573 574 bool [Plane::Clip]([LineSegment] &line) const575 {576 return [Clip](line.[a], line.[b]);577 }578 579 int [Plane::Clip](const [Line] &line, [Ray] &outRay) const580 {581 float t;582 bool intersects = [IntersectLinePlane]([PointOnPlane](), normal, line.[pos], line.[dir], &t);583 if (!intersects)584 {585 if ([SignedDistance](line.[pos]) <= 0.f)586 return 0; 587 else588 return 2; 589 }590 591 outRay.[pos] = line.[pos] + line.[dir] * t; 592 if ([Dot](line.[dir], normal) >= 0.f)593 outRay.[dir] = line.[dir];594 else595 outRay.[dir] = -line.[dir];596 597 return 1; 598 }599 600 int [Plane::Clip](const [Triangle] &triangle, [Triangle] &t1, [Triangle] &t2) const601 {602 bool side[3];603 side[0] = [IsOnPositiveSide](triangle.[a]);604 side[1] = [IsOnPositiveSide](triangle.[b]);605 side[2] = [IsOnPositiveSide](triangle.[c]);606 int nPos = (side[0] ? 1 : 0) + (side[1] ? 1 : 0) + (side[2] ? 1 : 0);607 if (nPos == 0) 608 return 0;609 610 t1 = triangle;611 612 if (nPos == 3) 613 return 1;614 615 if (nPos == 1)616 {617 if (side[1])618 {619 [float3] tmp = t1.[a];620 t1.[a] = t1.[b];621 t1.[b] = t1.[c];622 t1.[c] = tmp;623 }624 else if (side[2])625 {626 [float3] tmp = t1.[a];627 t1.[a] = t1.[c];628 t1.[c] = t1.[b];629 t1.[b] = tmp;630 }631 632 633 float t;634 [Intersects]([LineSegment](t1.[a], t1.[b]), &t);635 t1.[b] = t1.[a] + (t1.[b]-t1.[a])*t;636 [Intersects]([LineSegment](t1.[a], t1.[c]), &t);637 t1.[c] = t1.[a] + (t1.[c]-t1.[a])*t;638 return 1;639 }640 641 if (!side[1])642 {643 [float3] tmp = t1.[a];644 t1.[a] = t1.[b];645 t1.[b] = t1.[c];646 t1.[c] = tmp;647 }648 else if (!side[2])649 {650 [float3] tmp = t1.[a];651 t1.[a] = t1.[c];652 t1.[c] = t1.[b];653 t1.[b] = tmp;654 }655 656 657 float t, r;658 [Intersects]([LineSegment](t1.[a], t1.[b]), &t);659 [float3] ab = t1.[a] + (t1.[b]-t1.[a])*t;660 [Intersects]([LineSegment](t1.[a], t1.[c]), &r);661 [float3] ac = t1.[a] + (t1.[c]-t1.[a])*t;662 t1.[a] = ab;663 664 t2.[a] = t1.[c];665 t2.[b] = ac;666 t2.[c] = ab;667 668 return 2;669 }670 671 bool [Plane::IsParallel](const [Plane] &plane, float epsilon) const672 {673 return normal.[Equals](plane.[normal], epsilon);674 }675 676 bool [Plane::PassesThroughOrigin](float epsilon) const677 {678 return fabs(d) <= epsilon;679 }680 681 float [Plane::DihedralAngle](const [Plane] &plane) const682 {683 [assume](false && "Not implemented!"); 684 return false;685 }686 687 [Circle] [Plane::GenerateCircle](const [float3] &circleCenter, float radius) const688 {689 [assume](false && "Not implemented!"); 690 return [Circle]();691 }692 693 [Plane] [operator *](const [float3x3] &transform, const [Plane] &plane)694 {695 [Plane] p(plane);696 p.Transform(transform);697 return p;698 }699 700 [Plane] [operator *](const [float3x4] &transform, const [Plane] &plane)701 {702 [Plane] p(plane);703 p.Transform(transform);704 return p;705 }706 707 [Plane] [operator *](const [float4x4] &transform, const [Plane] &plane)708 {709 [Plane] p(plane);710 p.Transform(transform);711 return p;712 }713 714 [Plane] [operator *](const [Quat] &transform, const [Plane] &plane)715 {716 [Plane] p(plane);717 p.Transform(transform);718 return p;719 }720 721 #ifdef MATH_ENABLE_STL_SUPPORT722 std::string Plane::ToString() const723 {724 char str[256];725 sprintf(str, "Plane(Normal:(%.2f, %.2f, %.2f) d:%.2f)", normal.[x], normal.[y], normal.[z], d);726 return str;727 }728 #endif729 730 [MATH_END_NAMESPACE] Go back to previous page