// Copyright (C) 2002-2006 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #pragma once #include "Vector3D.h" #include "Line3D.h" #include "Plane3D.h" #include "Box3D.h" namespace Irrlicht { namespace Core { /// /// 3D triangle class for doing collision detection and other things. /// This class has been ported directly from the native C++ Irrlicht Engine, so it may not /// be 100% complete yet and the design may not be 100% .NET like. /// public __value class Triangle3D { public: /// /// Determinates if the triangle is totally inside a bounding box. /// /// Box to check. /// Returns true if the triangle is withing the box /// and false if it is not. bool IsTotalInsideBox(Box3D box) { return (box.IsPointInside(pointA) && box.IsPointInside(pointB) && box.IsPointInside(pointC)); } /// /// Returns the closest point on a triangle to a point on the same plane. /// /// Vector3D ClosestPointOnTriangle(Vector3D p) { Vector3D rab = Line3D(pointA, pointB).GetClosestPoint(p); Vector3D rbc = Line3D(pointB, pointC).GetClosestPoint(p); Vector3D rca = Line3D(pointC, pointA).GetClosestPoint(p); float d1 = (float)rab.GetDistanceFrom(p); float d2 = (float)rbc.GetDistanceFrom(p); float d3 = (float)rca.GetDistanceFrom(p); if (d1 < d2) return d1 < d3 ? rab : rca; return d2 < d3 ? rbc : rca; } /// /// Returns if a point is inside the triangle /// /// Point to test. Assumes that this point is already on the plane /// of the triangle. /// Returns true if the point is inside the triangle, otherwise false. bool IsPointInside(Vector3D p) { return (IsOnSameSide(p, pointA, pointB, pointC) && IsOnSameSide(p, pointB, pointA, pointC) && IsOnSameSide(p, pointC, pointA, pointB)); } /// /// Returns if a point is inside the triangle. This method is an implementation /// of the example used in a paper by Kasper Fauerby original written /// by Keidy from Mr-Gamemaker. /// /// Point to test. Assumes that this point is already on the plane /// of the triangle. /// Returns true if the point is inside the triangle, otherwise false. bool IsPointInsideFast(Vector3D p) { Vector3D f = pointB - pointA; Vector3D g = pointC - pointA; float a = f.DotProduct(f); float b = f.DotProduct(g); float c = g.DotProduct(g); float ac_bb = (a*c)-(b*b); Vector3D vp = p - pointA; float d = vp.DotProduct(f); float e = vp.DotProduct(g); float x = (d*c)-(e*b); float y = (e*a)-(d*b); float z = x+y-ac_bb; return (( ((unsigned int&)z)& ~(((unsigned int&)x)|((unsigned int&)y))) & 0x80000000)!=0; } bool IsOnSameSide(Vector3D p1, Vector3D p2, Vector3D a, Vector3D b) { Vector3D bminusa = b - a; Vector3D cp1 = bminusa.CrossProduct(p1 - a); Vector3D cp2 = bminusa.CrossProduct(p2 - a); return (cp1.DotProduct(cp2) > 0.0f); } /// /// Returns an intersection with a 3d line. /// /// Line to intersect with. /// Place to store the intersection point, if there is one. /// Returns true if there was an intersection, false if there was not. bool GetIntersectionWithLimitedLine(Line3D line, Vector3D outIntersection) { return GetIntersectionWithLine(line.start, line.GetVector(), outIntersection) && outIntersection.IsBetweenPoints(line.start, line.end); } /// /// Returns an intersection with a 3d line. /// Please note that also points are returned as intersection, which /// are on the line, but not between the start and end point of the line. /// If you want the returned point be between start and end, please /// use getIntersectionWithLimitedLine(). /// /// Vector of the line to intersect with. /// Point of the line to intersect with. /// Place to store the intersection point, if there is one. /// Returns true if there was an intersection, false if there was not. bool GetIntersectionWithLine(Vector3D linePoint, Vector3D lineVect, Vector3D outIntersection) { if (GetIntersectionOfPlaneWithLine(linePoint, lineVect, outIntersection)) return IsPointInside(outIntersection); return false; } /// /// Calculates the intersection between a 3d line and /// the plane the triangle is on. /// /// Vector of the line to intersect with. /// Point of the line to intersect with. /// Place to store the intersection point, if there is one. /// Returns true if there was an intersection, false if there was not. bool GetIntersectionOfPlaneWithLine(Vector3D linePoint, Vector3D lineVect, Vector3D outIntersection) { Vector3D normal = GetNormal(); float t2 = normal.DotProduct(lineVect); if (t2 == 0.0f) return false; float d = pointA.DotProduct(normal); float t =- (normal.DotProduct(linePoint) - d) / t2; outIntersection = linePoint + (lineVect * t); return true; } /// /// Returns the normal of the triangle. /// Please note: The normal is not normalized. /// Vector3D GetNormal() { return (pointB - pointA).CrossProduct(pointC - pointA); } /// /// Returns if the triangle is front of backfacing. /// /// Look direction. /// Returns true if the plane is front facing, which mean it would /// be visible, and false if it is backfacing. bool IsFrontFacting(Vector3D lookDirection) { Vector3D n = GetNormal(); n.Normalize(); return n.DotProduct(lookDirection) <= 0.0f; } /// /// Returns the plane of this triangle. /// Plane3D GetPlane() { return Plane3D(pointA, pointB, pointC); } void Set(Vector3D a, Vector3D b, Vector3D c) { pointA = a; pointB = b; pointC = c; } /// the three points of the triangle Vector3D pointA; Vector3D pointB; Vector3D pointC; }; } }