Oolite 1.91.0.7644-241112-7f5034b
Loading...
Searching...
No Matches
OOJSVector.m
Go to the documentation of this file.
1/*
2
3OOJSVector.m
4
5Oolite
6Copyright (C) 2004-2013 Giles C Williams and contributors
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
25#import "OOJSVector.h"
27
28#if OOLITE_GNUSTEP
29#import <GNUstepBase/GSObjCRuntime.h>
30#else
31#import <objc/objc-runtime.h>
32#endif
33
34#import "OOConstToString.h"
35#import "OOJSEntity.h"
36#import "OOJSQuaternion.h"
37
38
39static JSObject *sVectorPrototype;
40
41
42static BOOL GetThisVector(JSContext *context, JSObject *vectorObj, HPVector *outVector, NSString *method) NONNULL_FUNC;
43
44
45static JSBool VectorGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value);
46static JSBool VectorSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value);
47static void VectorFinalize(JSContext *context, JSObject *this);
48static JSBool VectorConstruct(JSContext *context, uintN argc, jsval *vp);
49
50// Methods
51static JSBool VectorToString(JSContext *context, uintN argc, jsval *vp);
52static JSBool VectorToSource(JSContext *context, uintN argc, jsval *vp);
53static JSBool VectorAdd(JSContext *context, uintN argc, jsval *vp);
54static JSBool VectorSubtract(JSContext *context, uintN argc, jsval *vp);
55static JSBool VectorDistanceTo(JSContext *context, uintN argc, jsval *vp);
56static JSBool VectorSquaredDistanceTo(JSContext *context, uintN argc, jsval *vp);
57static JSBool VectorMultiply(JSContext *context, uintN argc, jsval *vp);
58static JSBool VectorDot(JSContext *context, uintN argc, jsval *vp);
59static JSBool VectorAngleTo(JSContext *context, uintN argc, jsval *vp);
60static JSBool VectorFromCoordinateSystem(JSContext *context, uintN argc, jsval *vp);
61static JSBool VectorToCoordinateSystem(JSContext *context, uintN argc, jsval *vp);
62static JSBool VectorCross(JSContext *context, uintN argc, jsval *vp);
63static JSBool VectorTripleProduct(JSContext *context, uintN argc, jsval *vp);
64static JSBool VectorDirection(JSContext *context, uintN argc, jsval *vp);
65static JSBool VectorMagnitude(JSContext *context, uintN argc, jsval *vp);
66static JSBool VectorSquaredMagnitude(JSContext *context, uintN argc, jsval *vp);
67static JSBool VectorRotationTo(JSContext *context, uintN argc, jsval *vp);
68static JSBool VectorRotateBy(JSContext *context, uintN argc, jsval *vp);
69static JSBool VectorToArray(JSContext *context, uintN argc, jsval *vp);
70
71// Static methods
72static JSBool VectorStaticInterpolate(JSContext *context, uintN argc, jsval *vp);
73static JSBool VectorStaticRandom(JSContext *context, uintN argc, jsval *vp);
74static JSBool VectorStaticRandomDirection(JSContext *context, uintN argc, jsval *vp);
75static JSBool VectorStaticRandomDirectionAndLength(JSContext *context, uintN argc, jsval *vp);
76
77
78static JSClass sVectorClass =
79{
80 "Vector3D",
81 JSCLASS_HAS_PRIVATE,
82
83 JS_PropertyStub, // addProperty
84 JS_PropertyStub, // delProperty
85 VectorGetProperty, // getProperty
86 VectorSetProperty, // setProperty
87 JS_EnumerateStub, // enumerate
88 JS_ResolveStub, // resolve
89 JS_ConvertStub, // convert
90 VectorFinalize, // finalize
91 JSCLASS_NO_OPTIONAL_MEMBERS
92};
93
94
95enum
96{
97 // Property IDs
102
103
104static JSPropertySpec sVectorProperties[] =
105{
106 // JS name ID flags
110 { 0 }
111};
112
113
114static JSFunctionSpec sVectorMethods[] =
115{
116 // JS name Function min args
117 { "toSource", VectorToSource, 0, },
118 { "toString", VectorToString, 0, },
119 { "add", VectorAdd, 1, },
120 { "angleTo", VectorAngleTo, 1, },
121 { "cross", VectorCross, 1, },
122 { "direction", VectorDirection, 0, },
123 { "distanceTo", VectorDistanceTo, 1, },
124 { "dot", VectorDot, 1, },
125 { "fromCoordinateSystem", VectorFromCoordinateSystem, 1, },
126 { "magnitude", VectorMagnitude, 0, },
127 { "multiply", VectorMultiply, 1, },
128 { "rotateBy", VectorRotateBy, 1, },
129 { "rotationTo", VectorRotationTo, 1, },
130 { "squaredDistanceTo", VectorSquaredDistanceTo, 1, },
131 { "squaredMagnitude", VectorSquaredMagnitude, 0, },
132 { "subtract", VectorSubtract, 1, },
133 { "toArray", VectorToArray, 0, },
134 { "toCoordinateSystem", VectorToCoordinateSystem, 1, },
135 { "tripleProduct", VectorTripleProduct, 2, },
136 { 0 }
137};
138
139
140static JSFunctionSpec sVectorStaticMethods[] =
141{
142 // JS name Function min args
143 { "interpolate", VectorStaticInterpolate, 3, },
144 { "random", VectorStaticRandom, 0, },
145 { "randomDirection", VectorStaticRandomDirection, 0, },
146 { "randomDirectionAndLength", VectorStaticRandomDirectionAndLength, 0, },
147 { 0 }
148};
149
150
151// *** Public ***
152
153void InitOOJSVector(JSContext *context, JSObject *global)
154{
155 sVectorPrototype = JS_InitClass(context, global, NULL, &sVectorClass, VectorConstruct, 0, sVectorProperties, sVectorMethods, NULL, sVectorStaticMethods);
156}
157
158
159JSObject *JSVectorWithVector(JSContext *context, Vector vector)
160{
162
163 JSObject *result = NULL;
164 HPVector *private = NULL;
165
166 private = malloc(sizeof *private);
167 if (EXPECT_NOT(private == NULL)) return NULL;
168
169 *private = vectorToHPVector(vector);
170
171 result = JS_NewObject(context, &sVectorClass, sVectorPrototype, NULL);
172 if (result != NULL)
173 {
174 if (EXPECT_NOT(!JS_SetPrivate(context, result, private))) result = NULL;
175 }
176
177 if (EXPECT_NOT(result == NULL)) free(private);
178
179 return result;
180
182}
183
184
185BOOL VectorToJSValue(JSContext *context, Vector vector, jsval *outValue)
186{
188
189 JSObject *object = NULL;
190
191 assert(outValue != NULL);
192
193 object = JSVectorWithVector(context, vector);
194 if (EXPECT_NOT(object == NULL)) return NO;
195
196 *outValue = OBJECT_TO_JSVAL(object);
197 return YES;
198
200}
201
202JSObject *JSVectorWithHPVector(JSContext *context, HPVector vector)
203{
205
206 JSObject *result = NULL;
207 HPVector *private = NULL;
208
209 private = malloc(sizeof *private);
210 if (EXPECT_NOT(private == NULL)) return NULL;
211
212 *private = vector;
213
214 result = JS_NewObject(context, &sVectorClass, sVectorPrototype, NULL);
215 if (result != NULL)
216 {
217 if (EXPECT_NOT(!JS_SetPrivate(context, result, private))) result = NULL;
218 }
219
220 if (EXPECT_NOT(result == NULL)) free(private);
221
222 return result;
223
225}
226
227
228BOOL HPVectorToJSValue(JSContext *context, HPVector vector, jsval *outValue)
229{
231
232 JSObject *object = NULL;
233
234 assert(outValue != NULL);
235
236 object = JSVectorWithHPVector(context, vector);
237 if (EXPECT_NOT(object == NULL)) return NO;
238
239 *outValue = OBJECT_TO_JSVAL(object);
240 return YES;
241
243}
244
245
246BOOL NSPointToVectorJSValue(JSContext *context, NSPoint point, jsval *outValue)
247{
248 return VectorToJSValue(context, make_vector(point.x, point.y, 0), outValue);
249}
250
251
252BOOL JSValueToHPVector(JSContext *context, jsval value, HPVector *outVector)
253{
254 if (EXPECT_NOT(!JSVAL_IS_OBJECT(value))) return NO;
255
256 return JSObjectGetVector(context, JSVAL_TO_OBJECT(value), outVector);
257}
258
259BOOL JSValueToVector(JSContext *context, jsval value, Vector *outVector)
260{
261 if (EXPECT_NOT(!JSVAL_IS_OBJECT(value))) return NO;
262 HPVector tmp = kZeroHPVector;
263 BOOL result = JSObjectGetVector(context, JSVAL_TO_OBJECT(value), &tmp);
264 *outVector = HPVectorToVector(tmp);
265 return result;
266}
267
268
269#if OO_DEBUG
270
271typedef struct
272{
273 NSUInteger vectorCount;
274 NSUInteger entityCount;
275 NSUInteger arrayCount;
276 NSUInteger protoCount;
277 NSUInteger nullCount;
278 NSUInteger failCount;
279} VectorStatistics;
280static VectorStatistics sVectorConversionStats;
281
282
283@implementation PlayerEntity (JSVectorStatistics)
284
285// :setM vectorStats PS.callObjC("reportJSVectorStatistics")
286// :vectorStats
287
288- (NSString *) reportJSVectorStatistics
289{
290 VectorStatistics *stats = &sVectorConversionStats;
291
292 NSUInteger sum = stats->vectorCount + stats->entityCount + stats->arrayCount + stats->protoCount;
293 double convFac = 100.0 / sum;
294 if (sum == 0) convFac = 0;
295
296 return [NSString stringWithFormat:
297 @" vector-to-vector conversions: %lu (%g %%)\n"
298 " entity-to-vector conversions: %lu (%g %%)\n"
299 " array-to-vector conversions: %lu (%g %%)\n"
300 "prototype-to-zero conversions: %lu (%g %%)\n"
301 " null conversions: %lu (%g %%)\n"
302 " failed conversions: %lu (%g %%)\n"
303 " total: %lu",
304 (long)stats->vectorCount, stats->vectorCount * convFac,
305 (long)stats->entityCount, stats->entityCount * convFac,
306 (long)stats->arrayCount, stats->arrayCount * convFac,
307 (long)stats->protoCount, stats->protoCount * convFac,
308 (long)stats->nullCount, stats->nullCount * convFac,
309 (long)stats->failCount, stats->failCount * convFac,
310 (long)sum];
311}
312
313
314- (void) clearJSVectorStatistics
315{
316 memset(&sVectorConversionStats, 0, sizeof sVectorConversionStats);
317}
318
319@end
320
321#define COUNT(FIELD) do { sVectorConversionStats.FIELD++; } while (0)
322
323#else
324
325#define COUNT(FIELD) do {} while (0)
326
327#endif
328
329
330BOOL JSObjectGetVector(JSContext *context, JSObject *vectorObj, HPVector *outVector)
331{
333
334 assert(outVector != NULL);
335
336 HPVector *private = NULL;
337 jsuint arrayLength;
338 jsval arrayX, arrayY, arrayZ;
339 jsdouble x, y, z;
340
341 // vectorObj can legitimately be NULL, e.g. when JS_NULL is converted to a JSObject *.
342 if (EXPECT_NOT(vectorObj == NULL))
343 {
344 COUNT(nullCount);
345 return NO;
346 }
347
348 // If this is a (JS) Vector...
349 private = JS_GetInstancePrivate(context, vectorObj, &sVectorClass, NULL);
350 if (EXPECT(private != NULL))
351 {
352 COUNT(vectorCount);
353 *outVector = *private;
354 return YES;
355 }
356
357 // If it's an array...
358 if (EXPECT(JS_IsArrayObject(context, vectorObj)))
359 {
360 // ...and it has exactly three elements...
361 if (JS_GetArrayLength(context, vectorObj, &arrayLength) && arrayLength == 3)
362 {
363 if (JS_LookupElement(context, vectorObj, 0, &arrayX) &&
364 JS_LookupElement(context, vectorObj, 1, &arrayY) &&
365 JS_LookupElement(context, vectorObj, 2, &arrayZ))
366 {
367 // ...use the three numbers as [x, y, z]
368 if (JS_ValueToNumber(context, arrayX, &x) &&
369 JS_ValueToNumber(context, arrayY, &y) &&
370 JS_ValueToNumber(context, arrayZ, &z))
371 {
372 COUNT(arrayCount);
373 *outVector = make_HPvector(x, y, z);
374 return YES;
375 }
376 }
377 }
378 }
379
380 // If it's an entity, use its position.
381 if (OOJSIsMemberOfSubclass(context, vectorObj, JSEntityClass()))
382 {
383 COUNT(entityCount);
384 Entity *entity = [(id)JS_GetPrivate(context, vectorObj) weakRefUnderlyingObject];
385 *outVector = [entity position];
386 return YES;
387 }
388
389 /*
390 If it's actually a Vector3D but with no private field (this happens for
391 Vector3D.prototype)...
392
393 NOTE: it would be prettier to do this at the top when we handle normal
394 Vector3Ds, but it's a rare case which should be kept off the fast path.
395 */
396 if (JS_InstanceOf(context, vectorObj, &sVectorClass, NULL))
397 {
398 COUNT(protoCount);
399 *outVector = kZeroHPVector;
400 return YES;
401 }
402
403 COUNT(failCount);
404 return NO;
405
407}
408
409
410static BOOL GetThisVector(JSContext *context, JSObject *vectorObj, HPVector *outVector, NSString *method)
411{
412 if (EXPECT(JSObjectGetVector(context, vectorObj, outVector))) return YES;
413
414 jsval arg = OBJECT_TO_JSVAL(vectorObj);
415 OOJSReportBadArguments(context, @"Vector3D", method, 1, &arg, @"Invalid target object", @"Vector3D");
416 return NO;
417}
418
419
420BOOL JSVectorSetVector(JSContext *context, JSObject *vectorObj, Vector vector)
421{
422 return JSVectorSetHPVector(context,vectorObj,vectorToHPVector(vector));
423}
424
425
426BOOL JSVectorSetHPVector(JSContext *context, JSObject *vectorObj, HPVector vector)
427{
429
430 HPVector *private = NULL;
431
432 if (EXPECT_NOT(vectorObj == NULL)) return NO;
433
434 private = JS_GetInstancePrivate(context, vectorObj, &sVectorClass, NULL);
435 if (private != NULL) // If this is a (JS) Vector...
436 {
437 *private = vector;
438 return YES;
439 }
440
441 if (JS_InstanceOf(context, vectorObj, &sVectorClass, NULL))
442 {
443 // Silently fail for the prototype.
444 return YES;
445 }
446
447 return NO;
448
450}
451
452
453static BOOL VectorFromArgumentListNoErrorInternal(JSContext *context, uintN argc, jsval *argv, HPVector *outVector, uintN *outConsumed, BOOL permitNumberList)
454{
456
457 double x, y, z;
458
459 if (EXPECT_NOT(argc == 0)) return NO;
460 assert(argv != NULL && outVector != NULL);
461
462 if (outConsumed != NULL) *outConsumed = 0;
463
464 // Is first object a vector, array or entity?
465 if (JSVAL_IS_OBJECT(argv[0]))
466 {
467 if (JSObjectGetVector(context, JSVAL_TO_OBJECT(argv[0]), outVector))
468 {
469 if (outConsumed != NULL) *outConsumed = 1;
470 return YES;
471 }
472 }
473
474 if (!permitNumberList) return NO;
475
476 // As a special case for VectorConstruct(), look for three numbers.
477 if (argc < 3) return NO;
478
479 // Given a string, JS_ValueToNumber() returns YES but provides a NaN number.
480 if (EXPECT_NOT(!JS_ValueToNumber(context, argv[0], &x) || isnan(x))) return NO;
481 if (EXPECT_NOT(!JS_ValueToNumber(context, argv[1], &y) || isnan(y))) return NO;
482 if (EXPECT_NOT(!JS_ValueToNumber(context, argv[2], &z) || isnan(z))) return NO;
483
484 // We got our three numbers.
485 *outVector = make_HPvector(x, y, z);
486 if (outConsumed != NULL) *outConsumed = 3;
487
488 return YES;
489
491}
492
493
494// EMMSTRAN: remove outConsumed, since it can only be 1 except in failure (constructor is an exception, but it uses VectorFromArgumentListNoErrorInternal() directly).
495BOOL VectorFromArgumentList(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, HPVector *outVector, uintN *outConsumed)
496{
497 if (VectorFromArgumentListNoErrorInternal(context, argc, argv, outVector, outConsumed, NO)) return YES;
498 else
499 {
500 OOJSReportBadArguments(context, scriptClass, function, argc, argv,
501 @"Could not construct vector from parameters",
502 @"Vector, Entity or array of three numbers");
503 return NO;
504 }
505}
506
507
508BOOL VectorFromArgumentListNoError(JSContext *context, uintN argc, jsval *argv, HPVector *outVector, uintN *outConsumed)
509{
510 return VectorFromArgumentListNoErrorInternal(context, argc, argv, outVector, outConsumed, NO);
511}
512
513
514// *** Implementation stuff ***
515
516static JSBool VectorGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
517{
518 if (!JSID_IS_INT(propID)) return YES;
519
521
522 HPVector vector;
523 OOHPScalar fValue;
524
525 if (EXPECT_NOT(!JSObjectGetVector(context, this, &vector))) return NO;
526
527 switch (JSID_TO_INT(propID))
528 {
529 case kVector_x:
530 fValue = vector.x;
531 break;
532
533 case kVector_y:
534 fValue = vector.y;
535 break;
536
537 case kVector_z:
538 fValue = vector.z;
539 break;
540
541 default:
542 OOJSReportBadPropertySelector(context, this, propID, sVectorProperties);
543 return NO;
544 }
545
546 return JS_NewNumberValue(context, fValue, value);
547
549}
550
551
552static JSBool VectorSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
553{
554 if (!JSID_IS_INT(propID)) return YES;
555
557
558 HPVector vector;
559 jsdouble dval;
560
561 if (EXPECT_NOT(!JSObjectGetVector(context, this, &vector))) return NO;
562 if (EXPECT_NOT(!JS_ValueToNumber(context, *value, &dval)))
563 {
564 OOJSReportBadPropertyValue(context, this, propID, sVectorProperties, *value);
565 return NO;
566 }
567
568 switch (JSID_TO_INT(propID))
569 {
570 case kVector_x:
571 vector.x = dval;
572 break;
573
574 case kVector_y:
575 vector.y = dval;
576 break;
577
578 case kVector_z:
579 vector.z = dval;
580 break;
581
582 default:
583 OOJSReportBadPropertySelector(context, this, propID, sVectorProperties);
584 return NO;
585 }
586
587 return JSVectorSetHPVector(context, this, vector);
588
590}
591
592
593static void VectorFinalize(JSContext *context, JSObject *this)
594{
596
597 Vector *private = NULL;
598
599 private = JS_GetInstancePrivate(context, this, &sVectorClass, NULL);
600 if (private != NULL)
601 {
602 free(private);
603 }
604
606}
607
608
609static JSBool VectorConstruct(JSContext *context, uintN argc, jsval *vp)
610{
612
613 HPVector vector = kZeroHPVector;
614 HPVector *private = NULL;
615 JSObject *this = NULL;
616
617 private = malloc(sizeof *private);
618 if (EXPECT_NOT(private == NULL)) return NO;
619
620 this = JS_NewObject(context, &sVectorClass, NULL, NULL);
621 if (EXPECT_NOT(this == NULL)) return NO;
622
623 if (argc != 0)
624 {
625 if (EXPECT_NOT(!VectorFromArgumentListNoErrorInternal(context, argc, OOJS_ARGV, &vector, NULL, YES)))
626 {
627 free(private);
628 OOJSReportBadArguments(context, NULL, NULL, argc, OOJS_ARGV,
629 @"Could not construct vector from parameters",
630 @"Vector, Entity or array of three numbers");
631 return NO;
632 }
633 }
634
635 *private = vector;
636
637 if (EXPECT_NOT(!JS_SetPrivate(context, this, private)))
638 {
639 free(private);
640 return NO;
641 }
642
644
646}
647
648
649// *** Methods ***
650
651// toString() : String
652static JSBool VectorToString(JSContext *context, uintN argc, jsval *vp)
653{
654 OOJS_NATIVE_ENTER(context)
655
656 HPVector thisv;
657
658 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"toString"))) return NO;
659
660 OOJS_RETURN_OBJECT(HPVectorDescription(thisv));
661
663}
664
665
666// toSource() : String
667static JSBool VectorToSource(JSContext *context, uintN argc, jsval *vp)
668{
669 OOJS_NATIVE_ENTER(context)
670
671 HPVector thisv;
672
673 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"toSource"))) return NO;
674
675 NSString *str = [NSString stringWithFormat:@"Vector3D(%g, %g, %g)", thisv.x, thisv.y, thisv.z];
677
679}
680
681
682// add(v : vectorExpression) : Vector3D
683static JSBool VectorAdd(JSContext *context, uintN argc, jsval *vp)
684{
686
687 HPVector thisv, thatv, result;
688
689 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"add"))) return NO;
690 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"add", argc, OOJS_ARGV, &thatv, NULL))) return NO;
691
692 result = HPvector_add(thisv, thatv);
693
694 OOJS_RETURN_HPVECTOR(result);
695
697}
698
699
700// subtract(v : vectorExpression) : Vector3D
701static JSBool VectorSubtract(JSContext *context, uintN argc, jsval *vp)
702{
704
705 HPVector thisv, thatv, result;
706
707 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"subtract"))) return NO;
708 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"subtract", argc, OOJS_ARGV, &thatv, NULL))) return NO;
709
710 result = HPvector_subtract(thisv, thatv);
711
712 OOJS_RETURN_HPVECTOR(result);
713
715}
716
717
718// distanceTo(v : vectorExpression) : Number
719static JSBool VectorDistanceTo(JSContext *context, uintN argc, jsval *vp)
720{
722
723 HPVector thisv, thatv;
724 double result;
725
726 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"distanceTo"))) return NO;
727 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"distanceTo", argc, OOJS_ARGV, &thatv, NULL))) return NO;
728
729 result = HPdistance(thisv, thatv);
730
731 OOJS_RETURN_DOUBLE(result);
732
734}
735
736
737// squaredDistanceTo(v : vectorExpression) : Number
738static JSBool VectorSquaredDistanceTo(JSContext *context, uintN argc, jsval *vp)
739{
741
742 HPVector thisv, thatv;
743 double result;
744
745 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"squaredDistanceTo"))) return NO;
746 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"squaredDistanceTo", argc, OOJS_ARGV, &thatv, NULL))) return NO;
747
748 result = HPdistance2(thisv, thatv);
749
750 OOJS_RETURN_DOUBLE(result);
751
753}
754
755
756// multiply(n : Number) : Vector3D
757static JSBool VectorMultiply(JSContext *context, uintN argc, jsval *vp)
758{
760
761 HPVector thisv, result;
762 double scalar;
763
764 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"multiply"))) return NO;
765 if (EXPECT_NOT(!OOJSArgumentListGetNumber(context, @"Vector3D", @"multiply", argc, OOJS_ARGV, &scalar, NULL))) return NO;
766
767 result = HPvector_multiply_scalar(thisv, scalar);
768
769 OOJS_RETURN_HPVECTOR(result);
770
772}
773
774
775// dot(v : vectorExpression) : Number
776static JSBool VectorDot(JSContext *context, uintN argc, jsval *vp)
777{
779
780 HPVector thisv, thatv;
781 double result;
782
783 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"dot"))) return NO;
784 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"dot", argc, OOJS_ARGV, &thatv, NULL))) return NO;
785
786 result = HPdot_product(thisv, thatv);
787
788 OOJS_RETURN_DOUBLE(result);
789
791}
792
793
794// angleTo(v : vectorExpression) : Number
795static JSBool VectorAngleTo(JSContext *context, uintN argc, jsval *vp)
796{
798
799 HPVector thisv, thatv;
800 double result;
801
802 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"angleTo"))) return NO;
803 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"angleTo", argc, OOJS_ARGV, &thatv, NULL))) return NO;
804
805 result = HPdot_product(HPvector_normal(thisv), HPvector_normal(thatv));
806 if (result > 1.0) result = 1.0;
807 if (result < -1.0) result = -1.0;
808 // for identical vectors the dot_product sometimes returns a value > 1.0 because of rounding errors, resulting
809 // in an undefined result for the acos.
810 result = acos(result);
811
812 OOJS_RETURN_DOUBLE(result);
813
815}
816
817
818// cross(v : vectorExpression) : Vector3D
819static JSBool VectorCross(JSContext *context, uintN argc, jsval *vp)
820{
822
823 HPVector thisv, thatv, result;
824
825 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"cross"))) return NO;
826 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"cross", argc, OOJS_ARGV, &thatv, NULL))) return NO;
827
828 result = HPtrue_cross_product(thisv, thatv);
829
830 OOJS_RETURN_HPVECTOR(result);
831
833}
834
835
836// tripleProduct(v : vectorExpression, u : vectorExpression) : Number
837static JSBool VectorTripleProduct(JSContext *context, uintN argc, jsval *vp)
838{
840
841 HPVector thisv, thatv, theotherv;
842 double result;
843 uintN consumed;
844 jsval *argv = OOJS_ARGV;
845
846 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"tripleProduct"))) return NO;
847 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"tripleProduct", argc, argv, &thatv, &consumed))) return NO;
848 argc -= consumed;
849 argv += consumed;
850 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"tripleProduct", argc, argv, &theotherv, NULL))) return NO;
851
852 result = HPtriple_product(thisv, thatv, theotherv);
853
854 OOJS_RETURN_DOUBLE(result);
855
857}
858
859
860// direction() : Vector3D
861static JSBool VectorDirection(JSContext *context, uintN argc, jsval *vp)
862{
864
865 HPVector thisv, result;
866
867 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"direction"))) return NO;
868
869 result = HPvector_normal(thisv);
870
871 OOJS_RETURN_HPVECTOR(result);
872
874}
875
876
877// magnitude() : Number
878static JSBool VectorMagnitude(JSContext *context, uintN argc, jsval *vp)
879{
881
882 HPVector thisv;
883 double result;
884
885 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"magnitude"))) return NO;
886
887 result = HPmagnitude(thisv);
888
889 OOJS_RETURN_DOUBLE(result);
890
892}
893
894
895// squaredMagnitude() : Number
896static JSBool VectorSquaredMagnitude(JSContext *context, uintN argc, jsval *vp)
897{
899
900 HPVector thisv;
901 double result;
902
903 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"squaredMagnitude"))) return NO;
904
905 result = HPmagnitude2(thisv);
906
907 OOJS_RETURN_DOUBLE(result);
908
910}
911
912
913// rotationTo(v : vectorExpression [, limit : Number]) : Quaternion
914static JSBool VectorRotationTo(JSContext *context, uintN argc, jsval *vp)
915{
917
918 HPVector thisv, thatv;
919 double limit;
920 BOOL gotLimit;
921 Quaternion result;
922 uintN consumed;
923 jsval *argv = OOJS_ARGV;
924
925 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"rotationTo"))) return NO;
926 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"rotationTo", argc, OOJS_ARGV, &thatv, &consumed))) return NO;
927
928 argc -= consumed;
929 argv += consumed;
930 if (argc != 0) // limit parameter is optional.
931 {
932 if (EXPECT_NOT(!OOJSArgumentListGetNumber(context, @"Vector3D", @"rotationTo", argc, argv, &limit, NULL))) return NO;
933 gotLimit = YES;
934 }
935 else gotLimit = NO;
936
937 if (gotLimit) result = quaternion_limited_rotation_between(HPVectorToVector(thisv), HPVectorToVector(thatv), limit);
938 else result = quaternion_rotation_between(HPVectorToVector(thisv), HPVectorToVector(thatv));
939
941
943}
944
945
946// rotateBy(q : quaternionExpression) : Vector3D
947static JSBool VectorRotateBy(JSContext *context, uintN argc, jsval *vp)
948{
950
951 HPVector thisv, result;
952 Quaternion q;
953
954 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"rotateBy"))) return NO;
955 if (EXPECT_NOT(!QuaternionFromArgumentList(context, @"Vector3D", @"rotateBy", argc, OOJS_ARGV, &q, NULL))) return NO;
956
957 result = quaternion_rotate_HPvector(q, thisv);
958
959 OOJS_RETURN_HPVECTOR(result);
960
962}
963
964
965// toArray() : Array
966static JSBool VectorToArray(JSContext *context, uintN argc, jsval *vp)
967{
969
970 HPVector thisv;
971 JSObject *result = NULL;
972 jsval nVal;
973
974 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"toArray"))) return NO;
975
976 result = JS_NewArrayObject(context, 0, NULL);
977 if (result != NULL)
978 {
979 // We do this at the top because the return value slot is a GC root.
980 OOJS_SET_RVAL(OBJECT_TO_JSVAL(result));
981
982 if (JS_NewNumberValue(context, thisv.x, &nVal) && JS_SetElement(context, result, 0, &nVal) &&
983 JS_NewNumberValue(context, thisv.y, &nVal) && JS_SetElement(context, result, 1, &nVal) &&
984 JS_NewNumberValue(context, thisv.z, &nVal) && JS_SetElement(context, result, 2, &nVal))
985 {
986 return YES;
987 }
988 // If we get here, the conversion and stuffing in the previous condition failed.
989 OOJS_SET_RVAL(JSVAL_VOID);
990 }
991
992 return YES;
993
995}
996
997
998// toCoordinateSystem(coordScheme : String)
999static JSBool VectorToCoordinateSystem(JSContext *context, uintN argc, jsval *vp)
1000{
1001 OOJS_NATIVE_ENTER(context)
1002
1003 HPVector thisv;
1004 NSString *coordScheme = nil;
1005 HPVector result;
1006
1007 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"toCoordinateSystem"))) return NO;
1008
1009 if (EXPECT_NOT(argc < 1 ||
1010 (coordScheme = OOStringFromJSValue(context, OOJS_ARGV[0])) == nil))
1011 {
1012 OOJSReportBadArguments(context, @"Vector3D", @"toCoordinateSystem", MIN(argc, 1U), OOJS_ARGV, nil, @"coordinate system");
1013 return NO;
1014 }
1015
1016 OOJS_BEGIN_FULL_NATIVE(context)
1017 result = [UNIVERSE legacyPositionFrom:thisv asCoordinateSystem:coordScheme];
1019
1020 OOJS_RETURN_HPVECTOR(result);
1021
1023}
1024
1025
1026// fromCoordinateSystem(coordScheme : String)
1027static JSBool VectorFromCoordinateSystem(JSContext *context, uintN argc, jsval *vp)
1028{
1029 OOJS_NATIVE_ENTER(context)
1030
1031 HPVector thisv;
1032 NSString *coordScheme = nil;
1033 HPVector result;
1034
1035 if (EXPECT_NOT(!GetThisVector(context, OOJS_THIS, &thisv, @"fromCoordinateSystem"))) return NO;
1036
1037 if (EXPECT_NOT(argc < 1 ||
1038 (coordScheme = OOStringFromJSValue(context, OOJS_ARGV[0])) == nil))
1039 {
1040 OOJSReportBadArguments(context, @"Vector3D", @"fromCoordinateSystem", MIN(argc, 1U), OOJS_ARGV, nil, @"coordinate system");
1041 return NO;
1042 }
1043
1044 OOJS_BEGIN_FULL_NATIVE(context)
1045 NSString *arg = [NSString stringWithFormat:@"%@ %f %f %f", coordScheme, thisv.x, thisv.y, thisv.z];
1046 result = [UNIVERSE coordinatesFromCoordinateSystemString:arg];
1048
1049 OOJS_RETURN_HPVECTOR(result);
1050
1052}
1053
1054
1055// *** Static methods ***
1056
1057
1058// interpolate(v : Vector3D, u : Vector3D, alpha : Number) : Vector3D
1059static JSBool VectorStaticInterpolate(JSContext *context, uintN argc, jsval *vp)
1060{
1062
1063 HPVector av, bv;
1064 double interp;
1065 HPVector result;
1066 uintN consumed;
1067 uintN inArgc = argc;
1068 jsval *argv = OOJS_ARGV;
1069 jsval *inArgv = argv;
1070
1071 if (EXPECT_NOT(argc < 3)) goto INSUFFICIENT_ARGUMENTS;
1072 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"interpolate", argc, argv, &av, &consumed))) return NO;
1073 argc -= consumed;
1074 argv += consumed;
1075 if (EXPECT_NOT(argc < 2)) goto INSUFFICIENT_ARGUMENTS;
1076 if (EXPECT_NOT(!VectorFromArgumentList(context, @"Vector3D", @"interpolate", argc, argv, &bv, &consumed))) return NO;
1077 argc -= consumed;
1078 argv += consumed;
1079 if (EXPECT_NOT(argc < 1)) goto INSUFFICIENT_ARGUMENTS;
1080 if (EXPECT_NOT(!OOJSArgumentListGetNumber(context, @"Vector3D", @"interpolate", argc, argv, &interp, NULL))) return NO;
1081
1082 result = OOHPVectorInterpolate(av, bv, interp);
1083
1084 OOJS_RETURN_HPVECTOR(result);
1085
1086INSUFFICIENT_ARGUMENTS:
1087 OOJSReportBadArguments(context, @"Vector3D", @"interpolate", inArgc, inArgv,
1088 @"Insufficient parameters",
1089 @"vector expression, vector expression and number");
1090 return NO;
1091
1093}
1094
1095
1096// random([maxLength : Number]) : Vector3D
1097static JSBool VectorStaticRandom(JSContext *context, uintN argc, jsval *vp)
1098{
1100
1101 double maxLength;
1102
1103 if (argc == 0 || !OOJSArgumentListGetNumberNoError(context, argc, OOJS_ARGV, &maxLength, NULL)) maxLength = 1.0;
1104
1106
1108}
1109
1110
1111// randomDirection([scale : Number]) : Vector3D
1112static JSBool VectorStaticRandomDirection(JSContext *context, uintN argc, jsval *vp)
1113{
1115
1116 double scale;
1117
1118 if (argc == 0 || !OOJSArgumentListGetNumberNoError(context, argc, OOJS_ARGV, &scale, NULL)) scale = 1.0;
1119
1120 OOJS_RETURN_HPVECTOR(HPvector_multiply_scalar(OORandomUnitHPVector(), scale));
1121
1123}
1124
1125
1126// randomDirectionAndLength([maxLength : Number]) : Vector3D
1127static JSBool VectorStaticRandomDirectionAndLength(JSContext *context, uintN argc, jsval *vp)
1128{
1130
1131 double maxLength;
1132
1133 if (argc == 0 || !OOJSArgumentListGetNumberNoError(context, argc, OOJS_ARGV, &maxLength, NULL)) maxLength = 1.0;
1134
1136
1138}
1139
1140
#define EXPECT_NOT(x)
#define NONNULL_FUNC
#define EXPECT(x)
HPVector OOHPVectorRandomRadial(OOHPScalar maxLength)
Definition OOHPVector.m:98
const HPVector kZeroHPVector
Definition OOHPVector.m:28
HPVector OORandomUnitHPVector(void)
Definition OOHPVector.m:66
HPVector OOHPVectorRandomSpatial(OOHPScalar maxLength)
Definition OOHPVector.m:82
#define OOJS_PROFILE_EXIT
#define OOJS_PROFILE_EXIT_VOID
#define OOJS_END_FULL_NATIVE
#define OOJS_BEGIN_FULL_NATIVE(context)
#define OOJS_NATIVE_ENTER(cx)
#define OOJS_NATIVE_EXIT
#define OOJS_PROFILE_ENTER
OOINLINE JSClass * JSEntityClass(void)
Definition OOJSEntity.h:42
BOOL QuaternionFromArgumentList(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, Quaternion *outQuaternion, uintN *outConsumed) GCC_ATTR((nonnull(1
#define COUNT(FIELD)
BOOL BOOL JSVectorSetVector(JSContext *context, JSObject *vectorObj, Vector vector) GCC_ATTR((nonnull(1)))
Definition OOJSVector.m:420
BOOL BOOL VectorFromArgumentListNoError(JSContext *context, uintN argc, jsval *argv, HPVector *outVector, uintN *outConsumed) GCC_ATTR((nonnull(1
BOOL JSVectorSetHPVector(JSContext *context, JSObject *vectorObj, HPVector vector) GCC_ATTR((nonnull(1)))
Definition OOJSVector.m:426
BOOL JSObjectGetVector(JSContext *context, JSObject *vectorObj, HPVector *outVector) GCC_ATTR((nonnull(1
BOOL VectorFromArgumentList(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, HPVector *outVector, uintN *outConsumed) GCC_ATTR((nonnull(1
static JSBool VectorStaticRandomDirectionAndLength(JSContext *context, uintN argc, jsval *vp)
static JSBool VectorFromCoordinateSystem(JSContext *context, uintN argc, jsval *vp)
static JSBool VectorToArray(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:966
static JSBool VectorAdd(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:683
static JSBool VectorToString(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:652
static JSBool VectorCross(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:819
static JSBool VectorSubtract(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:701
static JSBool VectorStaticInterpolate(JSContext *context, uintN argc, jsval *vp)
static JSBool VectorRotateBy(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:947
static JSBool VectorToCoordinateSystem(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:999
static JSBool VectorDistanceTo(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:719
void InitOOJSVector(JSContext *context, JSObject *global)
Definition OOJSVector.m:153
static JSBool VectorMagnitude(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:878
static JSPropertySpec sVectorProperties[]
Definition OOJSVector.m:104
static JSBool VectorDot(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:776
static JSBool VectorRotationTo(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:914
static JSObject * sVectorPrototype
Definition OOJSVector.m:39
BOOL JSValueToVector(JSContext *context, jsval value, Vector *outVector)
Definition OOJSVector.m:259
static JSFunctionSpec sVectorMethods[]
Definition OOJSVector.m:114
static JSBool VectorTripleProduct(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:837
static JSBool VectorDirection(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:861
static JSBool VectorAngleTo(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:795
static JSFunctionSpec sVectorStaticMethods[]
Definition OOJSVector.m:140
BOOL JSValueToHPVector(JSContext *context, jsval value, HPVector *outVector)
Definition OOJSVector.m:252
BOOL JSObjectGetVector(JSContext *context, JSObject *vectorObj, HPVector *outVector)
Definition OOJSVector.m:330
static void VectorFinalize(JSContext *context, JSObject *this)
Definition OOJSVector.m:593
static JSBool VectorStaticRandom(JSContext *context, uintN argc, jsval *vp)
static JSBool VectorToSource(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:667
@ kVector_z
Definition OOJSVector.m:100
@ kVector_x
Definition OOJSVector.m:98
@ kVector_y
Definition OOJSVector.m:99
JSObject * JSVectorWithHPVector(JSContext *context, HPVector vector)
Definition OOJSVector.m:202
BOOL NSPointToVectorJSValue(JSContext *context, NSPoint point, jsval *outValue)
Definition OOJSVector.m:246
static BOOL VectorFromArgumentListNoErrorInternal(JSContext *context, uintN argc, jsval *argv, HPVector *outVector, uintN *outConsumed, BOOL permitNumberList)
Definition OOJSVector.m:453
BOOL VectorToJSValue(JSContext *context, Vector vector, jsval *outValue)
Definition OOJSVector.m:185
JSObject * JSVectorWithVector(JSContext *context, Vector vector)
Definition OOJSVector.m:159
static JSBool VectorConstruct(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:609
static JSBool VectorGetProperty(JSContext *context, JSObject *this, jsid propID, jsval *value)
Definition OOJSVector.m:516
static BOOL GetThisVector(JSContext *context, JSObject *vectorObj, HPVector *outVector, NSString *method) NONNULL_FUNC
Definition OOJSVector.m:410
static JSBool VectorSetProperty(JSContext *context, JSObject *this, jsid propID, JSBool strict, jsval *value)
Definition OOJSVector.m:552
static JSBool VectorSquaredMagnitude(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:896
static JSBool VectorSquaredDistanceTo(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:738
BOOL HPVectorToJSValue(JSContext *context, HPVector vector, jsval *outValue)
Definition OOJSVector.m:228
static JSClass sVectorClass
Definition OOJSVector.m:78
static JSBool VectorMultiply(JSContext *context, uintN argc, jsval *vp)
Definition OOJSVector.m:757
static JSBool VectorStaticRandomDirection(JSContext *context, uintN argc, jsval *vp)
BOOL OOJSArgumentListGetNumberNoError(JSContext *context, uintN argc, jsval *argv, double *outNumber, uintN *outConsumed)
#define OOJS_THIS
BOOL OOJSArgumentListGetNumber(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, double *outNumber, uintN *outConsumed)
#define OOJS_SET_RVAL(v)
#define OOJS_PROP_READWRITE_CB
#define OOJS_RETURN_DOUBLE(value)
#define OOJS_RETURN_OBJECT(o)
void OOJSReportBadPropertySelector(JSContext *context, JSObject *thisObj, jsid propID, JSPropertySpec *propertySpec)
OOINLINE BOOL OOJSIsMemberOfSubclass(JSContext *context, JSObject *object, JSClass *superclass)
NSString * OOStringFromJSValue(JSContext *context, jsval value)
#define OOJS_RETURN_QUATERNION(value)
#define OOJS_ARGV
#define OOJS_RETURN_JSOBJECT(o)
void OOJSReportBadPropertyValue(JSContext *context, JSObject *thisObj, jsid propID, JSPropertySpec *propertySpec, jsval value)
void OOJSReportBadArguments(JSContext *context, NSString *scriptClass, NSString *function, uintN argc, jsval *argv, NSString *message, NSString *expectedArgsDescription)
#define OOJS_RETURN_HPVECTOR(value)
double OOHPScalar
Definition OOMaths.h:69
#define MIN(A, B)
Definition OOMaths.h:111
return nil
HPVector quaternion_rotate_HPvector(Quaternion q, HPVector v)
Quaternion quaternion_rotation_between(Vector v0, Vector v1)
Quaternion quaternion_limited_rotation_between(Vector v0, Vector v1, float maxArc)
float y
float x
HPVector position
Definition Entity.h:112