#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_RECTANGLE2TRACER_H
#define NUCLEX_GEOMETRY_AREAS_TRACERS_RECTANGLE2TRACER_H
#include "Nuclex/Geometry/Config.h"
#include "Nuclex/Geometry/Areas/Rectangle2.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 rectangles
template
class Rectangle2Tracer {
/// Determines where a line enters and where it exits a rectangle
/// Line whose entry and exit times will be found
/// Rectangle that will be traced against the line
/// The times at which the line enters and leaves the rectangle
public: static LineContacts FindLineContacts(
const Lines::Line2 &line, const Rectangle2 &rectangle
) {
LineContacts contacts;
// If the line is not parallel to the Y axis, find out when it will cross
// the limits of the rectangle horizontally
if(line.Direction.X != 0) {
TScalar leftTouchTime = (rectangle.Min.X - line.Origin.X) / line.Direction.X;
TScalar rightTouchTime = (rectangle.Max.X - line.Origin.X) / line.Direction.X;
contacts = LineContacts::FromExtremes(leftTouchTime, rightTouchTime);
} else if((line.Origin.X < rectangle.Min.X) || (line.Origin.X >= rectangle.Max.X)) {
return LineContacts::None;
}
// If the line is not parallel to the X axis, find out when it will cross
// the limits of the rectangle vertically
if(line.Direction.Y != 0) {
TScalar topTouchTime = (rectangle.Min.Y - line.Origin.Y) / line.Direction.Y;
TScalar bottomTouchTime = (rectangle.Max.Y - line.Origin.Y) / line.Direction.Y;
// If the line was parallel to the Y axis (and we already made sure that it actually
// goes through the rectangle), only the Y axis needs to be taken into account.
if(line.Direction.X == 0) {
contacts = LineContacts::FromExtremes(topTouchTime, bottomTouchTime);
} else {
std::pair times = Math::Extremes(
topTouchTime, bottomTouchTime
);
// If the line already left the rectangle on one axis before entering it on
// the other, it is going past the corner of the rectangle without touching it
if((times.second < contacts.EntryTime) || (contacts.ExitTime < times.first)) {
return LineContacts::None;
}
contacts.EntryTime = Math::Max(times.first, contacts.EntryTime);
contacts.ExitTime = Math::Min(times.second, contacts.ExitTime);
}
} else if((line.Origin.Y < rectangle.Min.Y) || (line.Origin.Y > rectangle.Max.Y)) {
return LineContacts::None;
}
return contacts;
}
};
// ------------------------------------------------------------------------------------------- //
}}}} // namespace Nuclex::Geometry::Areas::Tracers
#endif // NUCLEX_GEOMETRY_AREAS_TRACERS_RECTANGLE2TRACER_H