-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathphutils.cpp
270 lines (214 loc) · 7.26 KB
/
phutils.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/*
@Copyright Looking Glass Studios, Inc.
1996,1997,1998,1999,2000 Unpublished Work.
*/
///////////////////////////////////////////////////////////////////////////////
// $Header: r:/t2repos/thief2/src/physics/phutils.cpp,v 1.22 2000/02/19 12:32:25 toml Exp $
//
//
//
#include <lg.h>
#include <stdlib.h>
#include <math.h>
#include <matrix.h>
#include <matrixs.h>
#include <phmod.h>
#include <phutils.h>
#include <memall.h>
#include <dbmem.h> // must be last header!
#undef rad2
///////////////////////////////////////////////////////////////////////////////
#define MAX_NUM_CONSTRAINTS (12)
void PhysRemNormComp(mxs_vector *vec, const mxs_vector *norm_list, int size)
{
mxs_vector orig;
mxs_vector inter;
int count = 0;
int i;
#ifndef SHIP
BOOL fully_constrained = FALSE;
#endif
if (size > MAX_NUM_CONSTRAINTS)
Warning(("PhysRemNormComp: too many constraints: %d, only using first %d\n", size, MAX_NUM_CONSTRAINTS));
count = (size > MAX_NUM_CONSTRAINTS) ? MAX_NUM_CONSTRAINTS : size;
mx_copy_vec(&orig, vec);
// First, special-case the two-vector case
int real_count = 0;
int real_norm_1 = -1;
int real_norm_2 = -1;
for (i = 0; i < count; i++)
{
if (mx_dot_vec(vec, &norm_list[i]) <= 0.0)
{
real_count++;
if (real_count > 2)
break;
if (real_norm_1 == -1)
real_norm_1 = i;
else
real_norm_2 = i;
}
}
if (real_count == 2)
{
mxs_vector test_vec;
test_vec = *vec;
PhysRemNormComp(&test_vec, norm_list[real_norm_1]);
if (mx_dot_vec(&test_vec, &norm_list[real_norm_2]) <= 0.0)
{
test_vec = *vec;
PhysRemNormComp(&test_vec, norm_list[real_norm_2]);
if (mx_dot_vec(&test_vec, &norm_list[real_norm_1]) <= 0.0)
{
PhysRemNormComp(vec, norm_list[real_norm_1], norm_list[real_norm_2]);
return;
}
}
}
// Do constraint pass
for (i=0; i<count; i++)
{
if (mx_dot_vec(vec, &norm_list[i]) <= 0.0)
PhysRemNormComp(vec, norm_list[i]);
}
// Save off intermediate vector
mx_copy_vec(&inter, vec);
// Check if the result is actually pointing us backward
if (mx_dot_vec(&inter, &orig) < 0.0)
{
mx_zero_vec(vec);
#ifndef SHIP
fully_constrained = TRUE;
#endif
}
// Now dot against all our constraints to make sure we're not still going in
for (i=0; i<count; i++)
{
mxs_real dot = mx_dot_vec(vec, &norm_list[i]);
if (dot < -0.0001)
{
mx_zero_vec(vec);
break;
}
}
}
void PhysRemNormComp(mxs_vector *vec, const mxs_vector &norm)
{
mxs_vector normal;
// remove all vec components normal to surface
mx_scale_vec(&normal, (mxs_vector *)&norm, min(0, mx_dot_vec(vec, (mxs_vector *)&norm)));
mx_subeq_vec(vec, &normal);
}
void PhysRemNormComp(mxs_vector *vec, const mxs_vector &norm1, const mxs_vector &norm2)
{
mxs_vector cross_prod;
mxs_vector component;
// remove all vec components within plane defined by norm1 and norm2
mx_cross_vec(&cross_prod, (mxs_vector *)&norm1, (mxs_vector *)&norm2);
if (IsZeroVector(cross_prod))
{
PhysRemNormComp(vec, norm1);
PhysRemNormComp(vec, norm2);
}
else
{
mx_normeq_vec(&cross_prod);
mx_scale_vec(&component, &cross_prod, mx_dot_vec(vec, &cross_prod));
mx_copy_vec(vec, &component);
}
}
///////////////////////////////////////////////////////////////////////////////
void PhysConstrain(mxs_vector *vec, const tConstraint *constraint_list, int size)
{
mxs_vector vec_list[MAX_NUM_CONSTRAINTS];
for (int i=0; i<size && i<MAX_NUM_CONSTRAINTS; i++)
vec_list[i] = constraint_list[i].dir;
PhysRemNormComp(vec, vec_list, size);
}
void PhysConstrain(mxs_vector *vec, const tConstraint &constraint)
{
PhysRemNormComp(vec, constraint.dir);
}
void PhysConstrian(mxs_vector *vec, const tConstraint &constraint1, const tConstraint &constraint2)
{
PhysRemNormComp(vec, constraint1.dir, constraint2.dir);
}
///////////////////////////////////////////////////////////////////////////////
//
// Solve for the first point on the parametric line p1+t*v1 whose distance to p2 is r. If such
// a point can be found then return TRUE and set t.
//
BOOL PhysSolveLnPtDistVec(const mxs_vector * p1, const mxs_vector * delta,
const mxs_vector * p2, mxs_real r,
mxs_real dt, mxs_real * t)
{
mxs_vector vel;
mx_scale_vec(&vel, delta, 1 / dt);
return PhysSolveLnPtDist(p1, &vel, p2, r, dt, t);
}
BOOL PhysSolveLnPtDist(const mxs_vector * p1, const mxs_vector * v1,
const mxs_vector * p2, mxs_real r,
mxs_real dt, mxs_real * t)
{
mxs_vector v1_true;
mxs_vector v1_norm;
mxs_vector v12, v23;
mxs_vector p3;
mxs_real v12_proj;
mxs_real rad_proj;
mxs_real v1_mag;
mxs_real v23_mag2;
mxs_real rad2 = (r * r);
// Setup
mx_scale_vec(&v1_true, (mxs_vector *)v1, dt);
mx_sub_vec(&v12, (mxs_vector *)p2, (mxs_vector *)p1);
mx_norm_vec(&v1_norm, &v1_true);
// Find length of projection of v12 onto v1
v12_proj = mx_dot_vec(&v12, &v1_norm);
// Find point along v1 to which v2 projects
mx_scale_add_vec(&p3, (mxs_vector *)p1, &v1_norm, v12_proj);
// Vector from p2 to p3, which is min dist of p2 from v1
mx_sub_vec(&v23, &p3, (mxs_vector *)p2);
// Reject if out of range
v23_mag2 = mx_mag2_vec(&v23);
if (v23_mag2 > rad2)
return FALSE;
// Find length of projection of radius (from p2) onto v1 using pythagorean theorum
rad_proj = sqrt(rad2 - v23_mag2);
v1_mag = mx_mag_vec(&v1_true);
// Find portion of v1 that is before the intersection, and scale
// the timeslice by that
*t = dt * ((v12_proj - rad_proj) / v1_mag);
return TRUE;
}
#if 0
mxs_real v1MagSq = mx_mag2_vec((mxs_vector *) v1);
mxs_vector v12,
v24;
mxs_real d13Sq,
d14Sq,
d24Sq;
mxs_real rSq = r * r;
mxs_real dpv12v1;
mxs_vector p4;
// Find the square of the length of the projection of v12 onto v1
mx_sub_vec(&v12, (mxs_vector *) p2, (mxs_vector *) p1);
dpv12v1 = mx_dot_vec(&v12, (mxs_vector *) v1);
d14Sq = (dpv12v1 * dpv12v1) / v1MagSq;
// Add to find point of projection
mx_scale_add_vec(&p4, (mxs_vector *) p1, (mxs_vector *) v1, sqrt(d14Sq / v1MagSq));
// Create vector from p2 normal to v1
mx_sub_vec(&v24, &p4, (mxs_vector *) p2);
d24Sq = mx_mag2_vec(&v24);
// Reject if too far away
if (d24Sq > rSq)
return FALSE;
// Find the square of the length of the projection of radius onto v1 (pythag)
d13Sq = rSq - d24Sq;
// Determine portion along v1 that d14 - d13 represents, and scale
// timeslice accordingly. Uses ((a - b) / c) ^ 2 == (a^2 - 2ab + b^2) / c^2.
*t = dt * sqrt((d14Sq - (2 * sqrt(d14Sq) * sqrt(d13Sq)) + d13Sq) / v1MagSq);
return TRUE;
}
#endif
///////////////////////////////////////////////////////////////////////////////