#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_VOLUMES_TRACERS_BOX3TRACER_H
#define NUCLEX_GEOMETRY_VOLUMES_TRACERS_BOX3TRACER_H
#include "Nuclex/Geometry/Config.h"
#include "Nuclex/Geometry/Volumes/Box3.h"
#include "Nuclex/Geometry/Lines/Line3.h"
#include "Nuclex/Geometry/LineContacts.h"
namespace Nuclex { namespace Geometry { namespace Volumes { namespace Tracers {
// ------------------------------------------------------------------------------------------- //
/// Determines contacts between lines and 3D boxes
template
class Box3Tracer {
/// Determines where a line enters and where it exits a box
/// Line whose entry and exit times will be found
/// Box that will be traced against the line
/// The times at which the line enters and leaves the box
public: static LineContacts FindLineContacts(
const Lines::Line3 &line, const Box3 &box
) {
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 = (box.Min.X - line.Origin.X) / line.Direction.X;
TScalar rightTouchTime = (box.Max.X - line.Origin.X) / line.Direction.X;
contacts.EntryTime = Math::Min(leftTouchTime, rightTouchTime);
contacts.ExitTime = Math::Max(leftTouchTime, rightTouchTime);
} else if((line.Offset.X < box.Min.X) || (line.Offset.X >= box.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) {
float topTouchTime = (box.Min.Y - line.Offset.Y) / line.Direction.Y;
float bottomTouchTime = (box.Max.Y - line.Offset.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.EntryTime = Math::Min(topTouchTime, bottomTouchTime);
contacts.ExitTime = Math::Max(topTouchTime, bottomTouchTime);
} else {
float verticalEntryTime = Math::Min(topTouchTime, bottomTouchTime);
float verticalExitTime = Math::Max(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((verticalExitTime < contacts.EntryTime) || (contacts.ExitTime < verticalEntryTime)) {
return LineContacts::None;
}
contacts.EntryTime = Math::Max(verticalEntryTime, contacts.EntryTime);
contacts.ExitTime = Math::Min(verticalExitTime, contacts.ExitTime);
}
} else if((line.Offset.Y < box.Min.Y) || (line.Offset.Y > box.Max.Y)) {
return LineContacts::None;
}
return contacts;
}
};
// ------------------------------------------------------------------------------------------- //
}}}} // namespace Nuclex::Geometry::Volumes::Tracers
#endif // NUCLEX_GEOMETRY_VOLUMES_TRACERS_BOX3TRACER_H