remove RSA's md4.c, replace by DP's
[xonotic/netradiant.git] / libs / math / line.h
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #if !defined(INCLUDED_MATH_LINE_H)
23 #define INCLUDED_MATH_LINE_H
24
25 /// \file
26 /// \brief Line data types and related operations.
27
28 #include "math/vector.h"
29 #include "math/plane.h"
30
31 /// \brief A line segment defined by a start point and and end point.
32 class Line
33 {
34 public:
35   Vector3 start, end;
36
37   Line()
38   {
39   }
40   Line(const Vector3& start_, const Vector3& end_) : start(start_), end(end_)
41   {
42   }
43 };
44
45 inline Vector3 line_closest_point(const Line& line, const Vector3& point)
46 {
47   Vector3 v = line.end - line.start;
48   Vector3 w = point - line.start;
49
50   double c1 = vector3_dot(w,v);
51   if ( c1 <= 0 )
52     return line.start;
53
54   double c2 = vector3_dot(v,v);
55   if ( c2 <= c1 )
56     return line.end;
57
58   return Vector3(line.start + v * (c1 / c2));
59 }
60
61
62 class Segment
63 {
64 public:
65   Vector3 origin, extents;
66
67   Segment()
68   {
69   }
70   Segment(const Vector3& origin_, const Vector3& extents_) :
71     origin(origin_), extents(extents_)
72   {
73   }
74 };
75
76
77 inline Segment segment_for_startend(const Vector3& start, const Vector3& end)
78 {
79   Segment segment;
80   segment.origin = vector3_mid(start, end);
81   segment.extents = vector3_subtracted(end, segment.origin);
82   return segment;
83 }
84
85 inline unsigned int segment_classify_plane(const Segment& segment, const Plane3& plane)
86 {
87   double distance_origin = vector3_dot(plane.normal(), segment.origin) + plane.dist();
88   
89   if (fabs(distance_origin) < fabs(vector3_dot(plane.normal(), segment.extents)))
90   {
91     return 1; // partially inside
92   }
93   else if (distance_origin < 0)
94   {
95     return 2; // totally inside
96   }
97   return 0; // totally outside
98 }
99
100
101 class Ray
102 {
103 public:
104   Vector3 origin, direction;
105
106   Ray()
107   {
108   }
109   Ray(const Vector3& origin_, const Vector3& direction_) :
110     origin(origin_), direction(direction_)
111   {
112   }
113 };
114
115 inline Ray ray_for_points(const Vector3& origin, const Vector3& p2)
116 {
117   return Ray(origin, vector3_normalised(vector3_subtracted(p2, origin)));
118 }
119
120 inline void ray_transform(Ray& ray, const Matrix4& matrix)
121 {
122   matrix4_transform_point(matrix, ray.origin);
123   matrix4_transform_direction(matrix, ray.direction);
124 }
125
126 // closest-point-on-line
127 inline double ray_squared_distance_to_point(const Ray& ray, const Vector3& point)
128 {
129   return vector3_length_squared(
130     vector3_subtracted(
131       point,
132       vector3_added(
133         ray.origin,
134         vector3_scaled(
135           ray.direction,
136           vector3_dot(
137             vector3_subtracted(point, ray.origin),
138             ray.direction
139           )
140         )
141       )
142     )
143   );
144 }
145
146 inline double ray_distance_to_plane(const Ray& ray, const Plane3& plane)
147 {
148   return -(vector3_dot(plane.normal(), ray.origin) - plane.dist()) / vector3_dot(ray.direction, plane.normal());
149 }
150
151 #endif