#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