mirror of
https://github.com/OPM/ResInsight.git
synced 2025-01-21 22:13:25 -06:00
533 lines
16 KiB
C++
533 lines
16 KiB
C++
//##################################################################################################
|
|
//
|
|
// Custom Visualization Core library
|
|
// Copyright (C) 2011-2013 Ceetron AS
|
|
//
|
|
// This library may be used under the terms of either the GNU General Public License or
|
|
// the GNU Lesser General Public License as follows:
|
|
//
|
|
// GNU General Public License Usage
|
|
// This library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 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 GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
|
|
// for more details.
|
|
//
|
|
// GNU Lesser General Public License Usage
|
|
// This library is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation; either version 2.1 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 GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
|
|
// for more details.
|
|
//
|
|
//##################################################################################################
|
|
|
|
|
|
#include "cvfBase.h"
|
|
#include "cvfRay.h"
|
|
#include "cvfBoundingBox.h"
|
|
#include "cvfPlane.h"
|
|
|
|
namespace cvf {
|
|
|
|
|
|
|
|
//==================================================================================================
|
|
///
|
|
/// \class cvf::Ray
|
|
/// \ingroup Geometry
|
|
///
|
|
/// A ray that can be used for intersection testing.
|
|
///
|
|
//==================================================================================================
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
Ray::Ray()
|
|
: m_origin(Vec3d::ZERO),
|
|
m_direction(-Vec3d::Z_AXIS),
|
|
m_minDistance(cvf::UNDEFINED_DOUBLE),
|
|
m_maxDistance(cvf::UNDEFINED_DOUBLE),
|
|
m_minDistanceSquared(cvf::UNDEFINED_DOUBLE),
|
|
m_maxDistanceSquared(cvf::UNDEFINED_DOUBLE),
|
|
m_distanceLimitedRay(false)
|
|
{
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
Ray::Ray(const Ray& other) : Object()
|
|
{
|
|
m_origin = other.origin();
|
|
m_direction = other.direction();
|
|
m_minDistance = other.m_minDistance;
|
|
m_maxDistance = other.m_maxDistance;
|
|
m_minDistanceSquared = other.m_minDistanceSquared;
|
|
m_maxDistanceSquared = other.m_maxDistanceSquared;
|
|
m_distanceLimitedRay = other.m_distanceLimitedRay;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
Ray::~Ray()
|
|
{
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Sets the origin (starting point) of the ray
|
|
//--------------------------------------------------------------------------------------------------
|
|
void Ray::setOrigin(const Vec3d& orig)
|
|
{
|
|
m_origin = orig;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const Vec3d& Ray::origin() const
|
|
{
|
|
return m_origin;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Sets the direction of the ray
|
|
//--------------------------------------------------------------------------------------------------
|
|
void Ray::setDirection(const Vec3d& dir)
|
|
{
|
|
m_direction = dir;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
const Vec3d& Ray::direction() const
|
|
{
|
|
return m_direction;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Transforms the origin and direction with the given transformation matrix
|
|
//--------------------------------------------------------------------------------------------------
|
|
void Ray::transform(const Mat4d& matrix)
|
|
{
|
|
m_origin.transformPoint(matrix);
|
|
m_direction.transformVector(matrix);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns this ray transformed with the given transformation matrix
|
|
//--------------------------------------------------------------------------------------------------
|
|
const Ray Ray::getTransformed(const Mat4d& matrix) const
|
|
{
|
|
Ray ray(*this);
|
|
ray.transform(matrix);
|
|
|
|
return ray;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns true if the ray intersects the triangle.
|
|
///
|
|
/// intersectionPoint (if not NULL) will be set to the ray intersection point on the triangle.
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool Ray::triangleIntersect(const Vec3d& v1, const Vec3d& v2, const Vec3d& v3, Vec3d* intersectionPoint) const
|
|
{
|
|
Vec3d v12 = v2 - v1;
|
|
Vec3d v13 = v3 - v1;
|
|
|
|
Vec3d n = (v12 ^ v13).getNormalized();
|
|
|
|
double det = n * direction();
|
|
|
|
if (det == 0.0f)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
double t = n * ((v1 - origin()) / det);
|
|
|
|
if (t < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Vec3d fp = origin() + direction()*t;
|
|
Vec3d pts[] = { v1, v2, v3, v1 };
|
|
|
|
int i;
|
|
for(i = 0; i < 3; i++)
|
|
{
|
|
Vec3d bi_norm = -((pts[i+1]-pts[i]) ^ n).getNormalized();
|
|
|
|
if (((fp-pts[i]) * bi_norm) < 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Distance filtering
|
|
if (m_distanceLimitedRay)
|
|
{
|
|
double distanceSquared = origin().pointDistanceSquared(fp);
|
|
|
|
if (m_minDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD && distanceSquared < m_minDistanceSquared)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (m_maxDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD && distanceSquared > m_maxDistanceSquared)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (intersectionPoint)
|
|
{
|
|
*intersectionPoint = fp;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns true if the ray intersects the quad.
|
|
///
|
|
/// intersectionPoint (if not NULL) will be set to the ray intersection point on the quad.
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool Ray::quadIntersect(const Vec3d& v1, const Vec3d& v2, const Vec3d& v3, const Vec3d& v4, Vec3d* intersectionPoint) const
|
|
{
|
|
Vec3d v12 = v2 - v1;
|
|
Vec3d v13 = v3 - v1;
|
|
|
|
Vec3d n = (v12 ^ v13).getNormalized(); // Quad Average normal
|
|
|
|
double det = n * direction(); // Length of projection of Quad normal to ray direction
|
|
|
|
if (det == 0.0f)
|
|
{
|
|
return false; // Ray parallel to average quad plane. Not quite accurate if origin is close to quad
|
|
}
|
|
|
|
double t = n * ((v1 - origin()) / det);
|
|
|
|
if (t < 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
Vec3d fp = origin() + direction()*t;
|
|
Vec3d pts[] = { v1, v2, v3, v4, v1 };
|
|
|
|
int i;
|
|
for(i = 0; i < 4; i++)
|
|
{
|
|
Vec3d bi_norm = -((pts[i+1] - pts[i]) ^ n).getNormalized(); // - (Edge x Quad normal) : Unit Vector in quad plane from edge into the quad
|
|
|
|
if (((fp - pts[i]) * bi_norm) < 0)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Distance filtering
|
|
if (m_distanceLimitedRay)
|
|
{
|
|
double distanceSquared = origin().pointDistanceSquared(fp);
|
|
|
|
if (m_minDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD && distanceSquared < m_minDistanceSquared)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (m_maxDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD && distanceSquared > m_maxDistanceSquared)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (intersectionPoint)
|
|
{
|
|
*intersectionPoint = fp;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns true if the ray intersects the bounding box.
|
|
///
|
|
/// intersectionPoint (if not NULL) will be set to the ray intersection point on the bounding box.
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool Ray::boxIntersect(const BoundingBox& box, Vec3d* intersectionPoint) const
|
|
{
|
|
if (!box.isValid()) return false;
|
|
|
|
const int RIGHT = 0;
|
|
const int LEFT = 1;
|
|
const int MIDDLE = 2;
|
|
|
|
|
|
// Find candidate planes; this loop can be avoided if rays cast all from the eye(assume perpsective view)
|
|
bool inside = true;
|
|
char quadrant[3];
|
|
double candidatePlane[3];
|
|
|
|
Vec3d min = box.min();
|
|
Vec3d max = box.max();
|
|
|
|
int i;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
if(m_origin[i] < min[i])
|
|
{
|
|
quadrant[i] = LEFT;
|
|
candidatePlane[i] = min[i];
|
|
inside = false;
|
|
}
|
|
else if (m_origin[i] > max[i])
|
|
{
|
|
quadrant[i] = RIGHT;
|
|
candidatePlane[i] = max[i];
|
|
inside = false;
|
|
}
|
|
else
|
|
{
|
|
quadrant[i] = MIDDLE;
|
|
}
|
|
}
|
|
|
|
// Ray origin inside bounding box
|
|
if (inside)
|
|
{
|
|
// Return intersection point
|
|
if (intersectionPoint) *intersectionPoint = m_origin;
|
|
|
|
return true;
|
|
}
|
|
|
|
// Calculate T distances to candidate planes
|
|
double maxT[3];
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
if (quadrant[i] != MIDDLE && m_direction[i] !=0.0f)
|
|
{
|
|
maxT[i] = (candidatePlane[i] - m_origin[i]) / m_direction[i];
|
|
}
|
|
else
|
|
{
|
|
maxT[i] = -1.0f;
|
|
}
|
|
}
|
|
|
|
// Get largest of the maxT's for final choice of intersection
|
|
int whichPlane = 0;
|
|
for (i = 1; i < 3; i++)
|
|
{
|
|
if (maxT[whichPlane] < maxT[i]) whichPlane = i;
|
|
}
|
|
|
|
// Check final candidate actually inside box
|
|
if (maxT[whichPlane] < 0.0f) return false;
|
|
|
|
Vec3d hitPoint;
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
if (whichPlane != i)
|
|
{
|
|
hitPoint[i] = m_origin[i] + maxT[whichPlane] * m_direction[i];
|
|
|
|
if (hitPoint[i] < min[i] || hitPoint[i] > max[i]) return false;
|
|
}
|
|
else
|
|
{
|
|
hitPoint[i] = candidatePlane[i];
|
|
}
|
|
}
|
|
|
|
// Distance filtering
|
|
if (m_distanceLimitedRay)
|
|
{
|
|
double distanceSquared = origin().pointDistanceSquared(hitPoint);
|
|
|
|
if (m_minDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD && distanceSquared < m_minDistanceSquared)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (m_maxDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD && distanceSquared > m_maxDistanceSquared)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (intersectionPoint)
|
|
{
|
|
*intersectionPoint = hitPoint;
|
|
}
|
|
|
|
// Ray hits box
|
|
return true;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Returns true if the ray intersects the ray
|
|
//--------------------------------------------------------------------------------------------------
|
|
bool Ray::planeIntersect(const Plane& plane, Vec3d* intersectionPoint) const
|
|
{
|
|
Vec3d pn = plane.normal();
|
|
double D = plane.D();
|
|
|
|
double vd = pn*m_direction;
|
|
|
|
// If vd > 0, the plane normal is pointing 'away' from the ray
|
|
// We want the plane normal facing the ray so flip direction of the plane
|
|
if (vd > 0)
|
|
{
|
|
pn *= -1;
|
|
D *= -1;
|
|
vd *= -1;
|
|
}
|
|
|
|
// No intersection ray and plane normal are parallel
|
|
if (Math::abs(vd) > std::numeric_limits<double>::epsilon())
|
|
{
|
|
double v0 = -(pn*m_origin + D);
|
|
double t = v0/vd;
|
|
if (t >= 0)
|
|
{
|
|
// Distance filtering
|
|
if (m_distanceLimitedRay)
|
|
{
|
|
double distanceSquared = origin().pointDistanceSquared(m_origin + t*m_direction);
|
|
|
|
if (m_minDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD && distanceSquared < m_minDistanceSquared)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (m_maxDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD && distanceSquared > m_maxDistanceSquared)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (intersectionPoint)
|
|
{
|
|
*intersectionPoint = m_origin + t*m_direction;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
///
|
|
//--------------------------------------------------------------------------------------------------
|
|
String Ray::debugString() const
|
|
{
|
|
String str = "Ray: ";
|
|
str += " origin: x=" + String::number(m_origin.x()) + " y=" + String::number(m_origin.y()) + " z=" + String::number(m_origin.z());
|
|
str += " direction: x=" + String::number(m_direction.x()) + " y=" + String::number(m_direction.y()) + " z=" + String::number(m_direction.z());
|
|
str += " minDist: " + String::number(m_minDistance);
|
|
str += " maxDist: " + String::number(m_maxDistance);
|
|
|
|
return str;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Set the minimum distance (from the origin) that the ray will hit.
|
|
///
|
|
/// Useful for limiting the ray when picking on models with clipping planes.
|
|
/// Set to tsv::UNDEFINED_DOUBLE
|
|
//--------------------------------------------------------------------------------------------------
|
|
void Ray::setMinimumDistance(double distance)
|
|
{
|
|
m_minDistance = distance;
|
|
|
|
if (m_minDistance >= 0 && m_minDistance < cvf::UNDEFINED_DOUBLE_THRESHOLD)
|
|
{
|
|
m_minDistanceSquared = m_minDistance*m_minDistance;
|
|
}
|
|
else
|
|
{
|
|
m_minDistanceSquared = cvf::UNDEFINED_DOUBLE;
|
|
}
|
|
|
|
m_distanceLimitedRay = (m_minDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD) || (m_maxDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Set the maximum distance (from the origin) that the ray will hit.
|
|
///
|
|
/// Useful for limiting the ray when picking on models with clipping planes
|
|
//--------------------------------------------------------------------------------------------------
|
|
void Ray::setMaximumDistance(double distance)
|
|
{
|
|
m_maxDistance = distance;
|
|
|
|
if (m_maxDistance >= 0 && m_maxDistance < cvf::UNDEFINED_DOUBLE_THRESHOLD)
|
|
{
|
|
m_maxDistanceSquared = m_maxDistance*m_maxDistance;
|
|
}
|
|
else
|
|
{
|
|
m_maxDistanceSquared = cvf::UNDEFINED_DOUBLE;
|
|
}
|
|
|
|
m_distanceLimitedRay = (m_minDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD) || (m_maxDistanceSquared < cvf::UNDEFINED_DOUBLE_THRESHOLD);
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Minimum distance (from the origin) that the ray will hit.
|
|
//--------------------------------------------------------------------------------------------------
|
|
double Ray::minimumDistance() const
|
|
{
|
|
return m_minDistance;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------------------------------------------
|
|
/// Maximum distance (from the origin) that the ray will hit
|
|
//--------------------------------------------------------------------------------------------------
|
|
double Ray::maximumDistance() const
|
|
{
|
|
return m_maxDistance;
|
|
}
|
|
|
|
} // namespace cvf
|