-
Notifications
You must be signed in to change notification settings - Fork 3
/
VectorVictor2.cpp
executable file
·580 lines (515 loc) · 17 KB
/
VectorVictor2.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
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
#include "VectorVictor2.hpp"
#include <iostream>
#include <math.h> // Roger, Roger.
//#include "Inertia_moment.h"
// The VectorVictor namespace //////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// VV2 Constructors ////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
VectorVictor::Vector2::Vector2 ()
{ // if nothing is passed, we assume the user wanted (0,0)
Set_values(0,0);
}
VectorVictor::Vector2::Vector2(long double ix, long double iy)
{ // otherwise we set the values of the vector as requested
Set_values(ix, iy);
#ifdef VECTORVICTOR_DEBUG
Nan_state = Is_nan();
#endif
}
// Set/Get Operators ///////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void VectorVictor::Vector2::Set_x(long double ix)
{ x = ix;
}
void VectorVictor::Vector2::Set_y(long double iy)
{ y = iy;
}
void VectorVictor::Vector2::Set_values(long double ix, long double iy)
{ x = ix;
y = iy;
}
// direct setters, nothing much to explain here
long double VectorVictor::Vector2::Get_x()
{ return x;
}
long double VectorVictor::Vector2::Get_y()
{ return y;
}
// and equally boring getters that just return the value itself
std::string VectorVictor::Vector2::Get_vector(std::string unit) // this would make a lot of sense as a template function for the cast type
{ // the idea behind this is to provide a nice interface for getting strings
// of a given vector formatted nicely with brackets, unit abbreviations
// (meters, kilograms, gees, etc.) and SI prefixes (kilo, mega, giga...)
std::string vector = "(";
// we create the start bracket
int exponent = 0;
// and initialize the exponent of the value used later
long double x_output = Get_x();
// since operations on the content of the Vector2 will need to change its
// values, we need to copy to a temporary variable for the duration
if((x_output >= 1000.0000)||(x_output <= -1000.00000))
{ // if the magnitude of the x value isnt within +/- 10^3,
// we are going to scale it back until it is within those bounds
// this is so that output displays printed to the game window can stay
// a nice short, easy to read length instead of a long bloated mess that
// jumps back & forth every time the order of magnitude changes
while((x_output >= 1000.0000)||(x_output <= -1000.00000))
{ // while we are outside of our target bounds, divide our magnitude
// by 10^3, and increase the exponent scale by 1 each time
x_output /= 1000.00000;
exponent++;
}
}
if(exponent > 7)
{ // as we will see in a minute, if we go past 10^7, I dont actually have
// a SI prefix for that, although Im sure it exists. If that is the case
// we scale the value up by 10^3 in magnitude again so that the display
// remains accurate, but no longer is concise
// this problem should be pretty rare though, as 10^7 is freaking Zetta,
// ^ Famous last words lol
while(exponent > 7)
{ x_output *= 1000.00;
exponent--;
// odd that last call to -- was missing. What the hell was it doing
// before?
// mildly concerning to say the least
}
}
vector.append(Convert_to_string((float)x_output , 4));
if(exponent != 0)
{ // if the exponent wasnt zero, we need to add a SI prefix to the vector
// so we sort through the possible options at every 3 orders of
// magnitude, and apply the one that fits to the string
switch(exponent)
{ case 1:
vector.append("k");
// kilo
break;
case 2:
vector.append("M");
// Mega
break;
case 3:
vector.append("G");
// Giga
break;
case 4:
vector.append("T");
// Tera // (actual usefulness pretty much ends here)
break;
case 5:
vector.append("P");
// Peta
break;
case 6:
vector.append("E");
// Exa
break;
case 7:
vector.append("Z");
// Zetta
break;
}
}
vector.append(unit);
// we append the unit of the vector after the si prefix, ie 'm'
vector.append(" , ");
// and we tack on the comma, since we have the y value to add as well
exponent = 0;
long double y_output = Get_y();
// same as with the x value, cant mess with our internal x & y values, so
// we make a copy to work with
if((y_output >= 1000.0000)||(y_output <= -1000.00000))
{ // if the magnitude of y isnt within the acceptable range, we scale it
// back until it is
while((y_output >= 1000.0000)||(y_output <= -1000.00000))
{ y_output /= 1000.00000;
exponent++;
}
}
if(exponent > 7)
{ // as we will see in a minute, if we go past 10^7, I dont actually have
// a SI prefix for that, although Im sure it exists. If that is the case
// we scale the value up by 10^3 in magnitude again so that the display
// remains accurate, but no longer is concise
// this problem should be pretty rare though, as 10^7 is freaking Zetta,
// ^ Famous last words lol
while(exponent > 7)
{ y_output *= 1000.00;
exponent--;
// odd that last call to -- was missing. What the hell was it doing
// before? That should have been an infinite loop!
// mildly concerning to say the least
}
}
vector.append(Convert_to_string((float)y_output , 4));
if(exponent != 0)
{ // if the exponent wasnt zero, we need to add a SI prefix before the
// unit, so we sort through and tack an appropriate one on
switch(exponent)
{ case 1:
vector.append("k");
// kilo
break;
case 2:
vector.append("M");
// Mega
break;
case 3:
vector.append("G");
// Giga
break;
case 4:
vector.append("T");
// Tera
break;
case 5:
vector.append("P");
// Peta
break;
case 6:
vector.append("E");
// Exa // (actual usefulness pretty much ends here)
break;
case 7:
vector.append("Z");
// Zetta
break;
}
}
vector.append(unit);
// we append the unit in question after the SI prefix
vector.append(")");
// add the close bracket in as well
return vector;
// and finally, we return the string that this function created
}
// Standard Class Operators ////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// important tools for a vector class, since they make objects of the type much
// more intuitive to work with
VectorVictor::Vector2 VectorVictor::Vector2::operator+ (VectorVictor::Vector2 pplus)
{ // still not particularly comfortable with standard operators just yet,
// what it does is obvious, but I really should learn this inside and out
VectorVictor::Vector2 tplus(this->Get_x(), this->Get_y());
tplus.x += pplus.x;
tplus.y += pplus.y;
return (tplus);
}
VectorVictor::Vector2 VectorVictor::Vector2::operator+= (VectorVictor::Vector2 pplus)
{ x += pplus.x;
y += pplus.y;
return (*this);
}
VectorVictor::Vector2 VectorVictor::Vector2::operator- (VectorVictor::Vector2 pminus)
{ VectorVictor::Vector2 tminus(this->Get_x(), this->Get_y());
tminus.x -= pminus.x;
tminus.y -= pminus.y;
return (tminus);
}
VectorVictor::Vector2 VectorVictor::Vector2::operator-= (VectorVictor::Vector2 pminus)
{ //bool nanState = Is_nan();
x -= pminus.x;
y -= pminus.y;
//this->Flag_nan("Nan created at VectorVictor::Vector2::operator-=", nanState);
return (*this);
}
VectorVictor::Vector2 VectorVictor::Vector2::operator= (const VectorVictor::Vector2 v)
{ // copy operator, copies each element to the current Vector2
#ifdef VECTORVICTOR_DEBUG
bool nanState = Is_nan();
#endif
x = v.x;
y = v.y;
#ifdef VECTORVICTOR_DEBUG
this->Flag_nan("Nan created at VectorVictor::Vector2::operator=", nanState);
#endif
return (*this);
}
VectorVictor::Vector2 VectorVictor::Vector2::operator * (const double c)
{
#ifdef VECTORVICTOR_DEBUG
bool nanState = Is_nan();
#endif
x *= c;
y *= c;
#ifdef VECTORVICTOR_DEBUG
this->Flag_nan("Nan created at VectorVictor::Vector2::operator *", nanState);
#endif
return (*this);
}
VectorVictor::Vector2 VectorVictor::Vector2::operator *= (const double c)
{ // multiply every element in the vector by some value c
x *= c;
y *= c;
return (*this);
}
bool VectorVictor::Vector2::operator != (const VectorVictor::Vector2 v)
{ // to check if the vectors are not equivalent, we specifically look at
// each element in each vector to see if any are different. If both of x
// and y are equivalent, we return false to indicate that it was ==
// specifically this function evaluates if the given functions are the
// *exact same*
if(this->x != v.x)
{ return true;
}
else
{ if(this->y != v.y)
{ return true;
}
else
{ return false;
// both elements were the same, just not your lucky day
}
}
}
bool VectorVictor::Vector2::operator == (const VectorVictor::Vector2 v)
{ // same idea as !=, now we just to check to see if each element in each
// vector is the same as the one in the other
// iff x1==x2 & y1==y2, we return true, indicating that
if(this->x == v.x)
{ if(this->y == v.y)
{ return true;
}
else
{ return false;
}
}
else
{ return false;
}
}
bool VectorVictor::Vector2::Is_nan()
{ if(this->x != this->x)
{ return true;
}
else
{ if(this->y != this->y)
{ return true;
}
else
{ return false;
}
}
}
bool VectorVictor::Vector2::Flag_nan(std::string message, bool &initial_state)
{ if(initial_state == false)
{ if(this->Is_nan())
{
#ifdef VECTORVICTOR_DEBUG
std::cout << message << std::endl;
#endif
return true;
}
else
{ return false;
}
}
else
{ return false;
}
}
// Extended Vector Operators ///////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void VectorVictor::Vector2::Normalize()
{ long double vector_magnitude = this->Get_vector_magnitude();
// we find the current magnitude of the vector
if(vector_magnitude > 0)
{ // and divide by it to adjust the vector to its correct value
Set_x(x/(vector_magnitude));
Set_y(y/(vector_magnitude));
}
// otherwise do nothing, cause I dont have a clue what we do if it is the
// zero vector
}
VectorVictor::Vector2 VectorVictor::Vector2::Vector_normal()
{ VectorVictor::Vector2 Output;
long double vector_magnitude = this->Get_vector_magnitude();
// we find our current vector magnitude
if(vector_magnitude > 0)
{
Output.Set_x(x/(vector_magnitude));
Output.Set_y(y/(vector_magnitude));
}
else
{ Output.Set_x(0);
Output.Set_y(0);
}
// set the output vector to the normalized value
return Output;
// and send the result on its merry way
// important to note: does *not* affect the contents of the calling
// Vector2 in any way
}
void VectorVictor::Vector2::Rotate_vector(long double rotation)
{ rotation = ((rotation/360)*2*Pi);
// we convert our rotation from degrees to radians, since standard library
// math calls want radians to do their calculations
long double new_x = ( (x*(cos(rotation)))+(y*(sin(rotation))) );
// AHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
// AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
// the variables are changing with respect to themselves!!!!
// AM WINNER PROGRAMMER, SUCH OF FULL oF WIN
y = ( (x*((-1)*sin(rotation)))+(y*(cos(rotation))) );
// multiply the vector by the 2d rotational matrix, rotating clockwise
// around the origin.
x = new_x;
// [cos(theta) sin(theta)]
// [-sin(theta cos(theta)]
// important to note that this vector affects the contents of the vector
// that calls it. If you want to get the rotated vector without affecting
// its current orientation, you need to call the next method below
}
VectorVictor::Vector2 VectorVictor::Vector2::Get_rotated_vector(long double rotation)
{ VectorVictor::Vector2 V_rotated(0, 0);
// pointless to be explicit about it being 0,0
// this would work better with setting its value as the parents
// x and y here instead
rotation = ((rotation/360)*2*Pi);
// convert our rotation from degrees to radians
V_rotated.x = ( (x*(cos(rotation)))+(y*(sin(rotation))) );
V_rotated.y = ( (x*((-1)*sin(rotation)))+(y*(cos(rotation))) );
// multiply the vector by the 2d rotational matrix, rotating clockwise
// around the origin.
// [cos(theta) sin(theta)]
// [-sin(theta cos(theta)]
return V_rotated;
// and send the resulting VV2 vector on its way
}
long double VectorVictor::Vector2::Get_vector_magnitude()
{ long double output, vx, vy;
// define the variables we will need to do operations on
vx = pow(x, 2);
vy = pow(y, 2);
// square both the x and y elements
// does this in an odd way, but the x and y of the object are not affected
// just passed by value to pow()
output = (vy + vx);
// add together the two components
output = sqrt(output);
// and run an expensive call to sqrt() to finish applying pythagorean
// theorem
return output;
}
long double VectorVictor::Vector2::Get_vector_magnitude_squared()
{ long double output, vx, vy;
vx = pow(x, 2);
vy = pow(y, 2);
// define our variables just like before
output = (vx+vy);
// add them up, but simply return that result as is, since we dont need to
// run that expensive call to sqrt()
return output;
}
// Destructor //////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
VectorVictor::Vector2::~Vector2(void)
{ // no memory allocations, so nothing much to do here
}
// Extended non-member Vector Operators ////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
long double VectorVictor::Get_dot_product(long double x1, long double y1, long double x2, long double y2)
{ long double output = ((x1*x2)+(y1*y2));
// not much to say here, just perform the standard dot-product operation
// & return the result. same thing below
return output;
}
long double VectorVictor::Get_dot_product(VectorVictor::Vector2 First_vector, VectorVictor::Vector2 Second_vector)
{ long double x1 = First_vector.Get_x();
long double y1 = First_vector.Get_y();
long double x2 = Second_vector.Get_x();
long double y2 = Second_vector.Get_y();
long double output = ((x1*x2)+(y1*y2));
// simple dot product, now done with vector objects passed
// this doesnt need to be this wasteful, we could just use the pass by
// value vv2s that were passed as parameters instead
return output;
}
long double VectorVictor::Get_vector_angle(VectorVictor::Vector2 First_vector, VectorVictor::Vector2 Second_vector)
{ // given that a dot b = ||a|| ||b|| cos(theta)
// we look to solve for the angle between the two vectors
// again, not sure where this is actually used, but good to have
long double theta, cos_theta;
long double dot_product, Magnitude1, Magnitude2;
dot_product = VectorVictor::Get_dot_product(First_vector, Second_vector);
// we find the dot product of the two vectors
Magnitude1 = First_vector.Get_vector_magnitude();
Magnitude2 = Second_vector.Get_vector_magnitude();
// and then we find the magnitudes of the vectors so we can get the
// value of cos(theta)
cos_theta = ((dot_product)/(Magnitude1*Magnitude2));
theta = acos(cos_theta);
// finally we run a call to arccos, perhaps a wee bit expensive, but dont
// know any other ways of doing it, so hey
return theta;
}
long double VectorVictor::Get_cross_product(Vector2 First_vector, Vector2 Second_vector)
{ long double x1, y1, x2, y2;
x1 = First_vector.Get_x();
y1 = First_vector.Get_y();
x2 = Second_vector.Get_x();
y2 = Second_vector.Get_y();
// we set up the variables from each vector
long double Output = ((x1*y2)-(x2*y1));
// then calculate the cross product, specifically the component in the k hat
// direction, since all vectors lie flat in the plane anyways
return Output;
}
long double VectorVictor::Get_vector_separation(Vector2 First_vector, Vector2 Second_vector)
{ long double dx = (First_vector.x - Second_vector.x);
long double dy = (First_vector.y - Second_vector.y);
long double rad = sqrt((dx*dx)+(dy*dy));
// simple enough, just applying pythagoras again
return rad;
}
long double Minimum(long double value1, long double value2)
{ if(value1 < value2)
{ return value1;
}
else
{ if(value1 == value2)
{ return value1;
// it dont matter
}
else
{ return value2;
}
}
}
long double Maximum(long double value1, long double value2)
{ if(value1 > value2)
{ return value1;
}
else
{ if(value1 == value2)
{ return value1;
// it dont matter
}
else
{ return value2;
}
}
}
bool In_range(long double boundary1, long double boundary2, long double target_value)
{ if((target_value >= Minimum(boundary1, boundary2))&&(target_value <= Maximum(boundary1, boundary2)))
{ // if the value falls in the range we're good to go
return true;
}
return false;
}
long double Absolute_value(long double value)
{ if(value < 0)
{ value = -value;
}
return value;
}
long double Smallest_value(std::vector<long double> &list)
{ long double smallest = list.at(0);
for(std::vector<long double>::iterator it = list.begin(); it != list.end(); ++it)
{ if((*it) < smallest)
{ smallest = (*it);
}
}
return smallest;
}