/* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant 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 2 of the License, or (at your option) any later version. GtkRadiant 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 for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined( INCLUDED_MATH_LINE_H ) #define INCLUDED_MATH_LINE_H /// \file /// \brief Line data types and related operations. #include "math/vector.h" #include "math/plane.h" /// \brief A line segment defined by a start point and and end point. class Line { public: Vector3 start, end; Line(){ } Line( const Vector3& start_, const Vector3& end_ ) : start( start_ ), end( end_ ){ } }; inline Vector3 line_closest_point( const Line& line, const Vector3& point ){ Vector3 v = line.end - line.start; Vector3 w = point - line.start; double c1 = vector3_dot( w,v ); if ( c1 <= 0 ) { return line.start; } double c2 = vector3_dot( v,v ); if ( c2 <= c1 ) { return line.end; } return Vector3( line.start + v * ( c1 / c2 ) ); } class Segment { public: Vector3 origin, extents; Segment(){ } Segment( const Vector3& origin_, const Vector3& extents_ ) : origin( origin_ ), extents( extents_ ){ } }; inline Segment segment_for_startend( const Vector3& start, const Vector3& end ){ Segment segment; segment.origin = vector3_mid( start, end ); segment.extents = vector3_subtracted( end, segment.origin ); return segment; } inline unsigned int segment_classify_plane( const Segment& segment, const Plane3& plane ){ double distance_origin = vector3_dot( plane.normal(), segment.origin ) + plane.dist(); if ( fabs( distance_origin ) < fabs( vector3_dot( plane.normal(), segment.extents ) ) ) { return 1; // partially inside } else if ( distance_origin < 0 ) { return 2; // totally inside } return 0; // totally outside } class Ray { public: Vector3 origin, direction; Ray(){ } Ray( const Vector3& origin_, const Vector3& direction_ ) : origin( origin_ ), direction( direction_ ){ } }; inline Ray ray_for_points( const Vector3& origin, const Vector3& p2 ){ return Ray( origin, vector3_normalised( vector3_subtracted( p2, origin ) ) ); } inline void ray_transform( Ray& ray, const Matrix4& matrix ){ matrix4_transform_point( matrix, ray.origin ); matrix4_transform_direction( matrix, ray.direction ); } // closest-point-on-line inline double ray_squared_distance_to_point( const Ray& ray, const Vector3& point ){ return vector3_length_squared( vector3_subtracted( point, vector3_added( ray.origin, vector3_scaled( ray.direction, vector3_dot( vector3_subtracted( point, ray.origin ), ray.direction ) ) ) ) ); } inline double ray_distance_to_plane( const Ray& ray, const Plane3& plane ){ return -( vector3_dot( plane.normal(), ray.origin ) - plane.dist() ) / vector3_dot( ray.direction, plane.normal() ); } #endif