#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2015 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #ifndef NUCLEX_GEOMETRY_AREAS_TRACERS_TRIANGLE2TRACER_H #define NUCLEX_GEOMETRY_AREAS_TRACERS_TRIANGLE2TRACER_H #include "Nuclex/Geometry/Config.h" #include "Nuclex/Geometry/Areas/Triangle2.h" #include "Nuclex/Geometry/Lines/Line2.h" #include "Nuclex/Geometry/LineContacts.h" namespace Nuclex { namespace Geometry { namespace Areas { namespace Tracers { // ------------------------------------------------------------------------------------------- // /// Determines contacts between lines and 2D triangles template class Triangle2Tracer { /// Determines where a line enters and where it exits a triangle /// /// Line whose entry and exit through the triangle will be determined /// /// Triangle the line will be checked against /// The times at which the line enters and leaves the triangle public: static LineContacts FindLineContacts( const Lines::Line2 &line, const Triangle2 &triangle ) { // Careful, line could start inside triangle - but it's a line, so negative // entry time is okay? TScalar abContact = findLineContact(line, triangle.A, triangle.B); TScalar bcContact = findLineContact(line, triangle.B, triangle.C); TScalar caContact = findLineContact(line, triangle.C, triangle.A); // A line can either cross none of the triangle's edges or two of them. // We consider any other number of crossed edges impossible (exactly hitting // a corner or such things are simply considered misses) if(Math::IsNan(abContact)) { if(Math::IsNan(bcContact)) { return LineContacts(caContact, caContact); } else if(Math::IsNan(caContact)) { return LineContacts(bcContact, bcContact); } else if(bcContact < caContact) { return LineContacts(bcContact, caContact); } else { return LineContacts(caContact, bcContact); } } else if(Math::IsNan(bcContact)) { if(Math::IsNan(caContact)) { return LineContacts(abContact, abContact); } else if(abContact < caContact) { return LineContacts(abContact, caContact); } else { return LineContacts(caContact, abContact); } } else { if(abContact < bcContact) { return LineContacts(abContact, bcContact); } else { return LineContacts(bcContact, abContact); } } } /// Determines where a line crosses a line segment /// Line whose time of crossing will be determined /// Point at which the line segment begins /// Point at which the line segment ends /// The time at which the line crosses the line segment private: static TScalar findLineContact( const Lines::Line2 &line, const Point2 &start, const Point2 &end ) { Vector2 segmentDirection = (end - start); // Time of intersection of the segment with the traced line. This allows us to see // if the segment hits the traced line inside its length. TScalar s = ( line.Direction.X * (line.Origin.Y - start.Y) - line.Direction.Y * (line.Origin.X - start.X) ) / (line.Direction.X * segmentDirection.Y - segmentDirection.X * line.Direction.Y); if((s >= 0) && (s < 1)) { TScalar t = ( segmentDirection.X * (line.Origin.Y - start.Y) - segmentDirection.Y * (line.Origin.X - start.X) ) / (line.Direction.X * segmentDirection.Y - segmentDirection.X * line.Direction.Y); return t; } else { return std::numeric_limits::signaling_NaN(); } } }; // ------------------------------------------------------------------------------------------- // }}}} // namespace Nuclex::Geometry::Areas::Tracers #endif // NUCLEX_GEOMETRY_AREAS_TRACERS_TRIANGLE2TRACER_H