1 package cz.cuni.amis.pogamut.base3d.worldview.object;
2
3 import java.beans.PropertyEditorManager;
4 import java.beans.PropertyEditorSupport;
5 import java.io.Serializable;
6 import java.util.Locale;
7 import java.util.regex.Matcher;
8 import java.util.regex.Pattern;
9
10 import javax.vecmath.Tuple3d;
11 import javax.vecmath.Vector3d;
12
13
14
15
16
17
18
19
20
21 public class Velocity implements ILocomotive, Serializable, Cloneable {
22
23
24
25 public static final Velocity NONE = new Velocity(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
26
27 public static final Velocity ZERO = new Velocity();
28
29 static {
30
31
32 PropertyEditorManager.registerEditor(Velocity.class, Velocity.PropertyEditor.class);
33 }
34
35
36
37
38 public static class PropertyEditor extends PropertyEditorSupport {
39
40 @Override
41 public String getAsText() {
42 if (getValue() != null) {
43 return getValue().toString();
44 } else {
45 return "null";
46 }
47 }
48
49 @Override
50 public void setAsText(String s) {
51 if ("null".equals(s.trim())) {
52 setValue(null);
53 } else {
54 double[] d = Location.PropertyEditor.parseNumberArray(s);
55 if (d.length != 3) {
56 throw new IllegalArgumentException();
57 }
58 setValue(new Velocity(d));
59 }
60 }
61 }
62
63 @Override
64 public Velocity clone() {
65 return new Velocity(this);
66 }
67
68 public Vector3d asVector3d() {
69 return new Vector3d(x, y, z);
70 }
71
72 public Location asLocation() {
73 return new Location(x, y, z);
74 }
75
76
77 public final double x;
78
79 public final double y;
80
81 public final double z;
82
83 private Integer hashCode = null;
84
85
86
87
88
89
90
91
92 public double getX() {
93 return x;
94 }
95
96
97
98
99
100
101 public double getY() {
102 return y;
103 }
104
105
106
107
108
109
110 public double getZ() {
111 return z;
112 }
113
114
115
116
117
118
119
120
121 public Velocity setX(double x) {
122 return new Velocity(x, this.y, this.z);
123 }
124
125
126
127
128
129
130 public Velocity setY(double y) {
131 return new Velocity(this.x, y, this.z);
132 }
133
134
135
136
137
138
139 public Velocity setZ(double z) {
140 return new Velocity(this.x, this.y, z);
141 }
142
143
144
145
146
147
148
149
150 public boolean isZero() {
151
152 return (x == 0) && (y == 0) && (z == 0);
153 }
154
155
156
157
158
159
160 public boolean isZero(double epsilon) {
161
162 return (Math.abs(x) < epsilon) && (Math.abs(y) < epsilon) && (Math.abs(z) < epsilon);
163 }
164
165
166
167
168
169
170 public boolean isPlanarZero() {
171
172 return (x == 0) && (y == 0);
173 }
174
175
176
177
178
179
180 public double size() {
181
182 return Math.sqrt(x * x + y * y + z * z);
183 }
184
185
186
187
188
189
190 public double sizeSquare() {
191
192 return x * x + y * y + z * z;
193 }
194
195
196
197
198
199
200
201
202 public Velocity normalize() {
203
204 double d = 1 / Math.sqrt(x * x + y * y + z * z);
205
206 return new Velocity(x * d, y * d, z * d);
207 }
208
209
210
211
212
213
214 public Velocity negate() {
215
216 return new Velocity(-x, -y, -z);
217 }
218
219
220
221
222
223
224 public Velocity absolute() {
225
226 return new Velocity(Math.abs(x), Math.abs(y), Math.abs(z));
227 }
228
229
230
231
232
233
234
235
236 public Velocity scale(double d) {
237
238 return new Velocity(x * d, y * d, z * d);
239 }
240
241
242
243
244
245
246
247
248
249
250 public double dot(Velocity v) {
251
252 return x * v.x + y * v.y + z * v.z;
253 }
254
255
256
257
258
259
260
261
262
263
264 public static double dot(Velocity v1, Velocity v2) {
265
266 return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
267 }
268
269
270
271
272
273
274
275
276
277
278 public Velocity cross(Velocity v) {
279
280 return new Velocity(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
281 }
282
283
284
285
286
287
288
289
290
291
292 public static Velocity cross(Velocity v1, Velocity v2) {
293
294 return new Velocity(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x);
295 }
296
297
298
299
300
301
302
303
304
305
306 public Velocity add(Velocity v) {
307
308 return new Velocity(x + v.x, y + v.y, z + v.z);
309 }
310
311
312
313
314
315
316
317
318
319
320 public static Velocity add(Velocity v1, Velocity v2) {
321
322 return new Velocity(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
323 }
324
325
326
327
328
329
330
331
332 public Velocity sub(Velocity v) {
333
334 return new Velocity(x - v.x, y - v.y, z - v.z);
335 }
336
337
338
339
340
341
342
343
344
345
346 public static Velocity sub(Velocity v1, Velocity v2) {
347
348 return new Velocity(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
349 }
350
351
352
353
354
355
356
357
358
359
360
361
362 public Velocity interpolate(Velocity v, double d) {
363
364 double d1 = 1.0D - d;
365
366 return new Velocity(d1 * x + d * v.x, d1 * y + d * v.y, d1 * z + d * v.z);
367 }
368
369
370
371
372
373
374
375
376
377
378
379
380 public static Velocity interpolate(Velocity v1, Velocity v2, double d) {
381
382 double d1 = 1.0D - d;
383
384 return new Velocity(d1 * v1.x + d * v2.x, d1 * v1.y + d * v2.y, d1 * v1.z + d * v2.z);
385 }
386
387
388
389
390
391
392 @Override
393 public int hashCode() {
394 if (hashCode == null) hashCode = computeHashCode();
395 return hashCode;
396 }
397
398
399
400
401
402
403
404
405
406 @Override
407 public boolean equals(Object obj) {
408 if (this == obj)
409 return true;
410 if (obj == null)
411 return false;
412 if (!(obj instanceof Velocity))
413 return false;
414 Velocity other = (Velocity) obj;
415 if (hashCode != other.hashCode) return false;
416 if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
417 return false;
418 if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
419 return false;
420 if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z))
421 return false;
422 return true;
423 }
424
425
426
427
428
429
430
431
432
433
434 public static boolean equal(Velocity v1, Velocity v2) {
435 if (v1 == null && v2 == null)
436 return true;
437 if (v1 == null || v2 == null)
438 return false;
439
440 return v1.equals(v2);
441 }
442
443
444
445
446
447
448
449
450
451
452
453
454 public boolean equals(Velocity v, double epsilon) {
455 double d;
456
457
458 d = x - v.x;
459 if ((d >= 0 ? d : -d) > epsilon)
460 return false;
461
462
463 d = y - v.y;
464 if ((d >= 0.0D ? d : -d) > epsilon)
465 return false;
466
467
468 d = z - v.z;
469 if ((d >= 0.0D ? d : -d) > epsilon)
470 return false;
471
472
473 return true;
474 }
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489 public static boolean equal(Velocity v1, Velocity v2, double epsilon) {
490 double d;
491
492
493 d = v1.x - v2.x;
494 if ((d >= 0 ? d : -d) > epsilon)
495 return false;
496
497
498 d = v1.y - v2.y;
499 if ((d >= 0.0D ? d : -d) > epsilon)
500 return false;
501
502
503 d = v1.z - v2.z;
504 if ((d >= 0.0D ? d : -d) > epsilon)
505 return false;
506
507
508 return true;
509 }
510
511
512
513
514
515
516
517
518 public Velocity align() {
519
520 return new Velocity(x, y, 0);
521 }
522
523
524
525
526
527
528
529
530
531
532
533
534 public Velocity sideways() {
535
536 return new Velocity(y, -x, 0);
537 }
538
539
540
541
542
543
544
545
546 @Override
547 public Velocity getVelocity() {
548 return this;
549 }
550
551
552
553
554
555
556 public Vector3d getVector3d() {
557 return new Vector3d(x, y, z);
558 }
559
560
561
562
563
564
565 private Velocity() {
566 this(0,0,0);
567 }
568
569
570
571
572
573
574
575 public Velocity(Velocity velocity) {
576 this(velocity.getX(), velocity.getY(), velocity.getZ());
577 }
578
579
580
581
582
583
584
585
586
587
588
589 public Velocity(double x, double y, double z) {
590 this.x = x;
591 this.y = y;
592 this.z = z;
593 }
594
595 private int computeHashCode() {
596 final int prime = 31;
597 int result = 1;
598 long temp;
599 temp = Double.doubleToLongBits(x);
600 result = prime * result + (int) (temp ^ (temp >>> 32));
601 temp = Double.doubleToLongBits(y);
602 result = prime * result + (int) (temp ^ (temp >>> 32));
603 temp = Double.doubleToLongBits(z);
604 result = prime * result + (int) (temp ^ (temp >>> 32));
605 return result;
606 }
607
608
609
610
611
612
613
614
615
616
617 public Velocity(double x, double y) {
618 this(x,y,0);
619 }
620
621
622
623
624
625
626
627
628 public Velocity(double d[]) {
629 if (d.length >= 1)
630 this.x = d[0];
631 else
632 this.x = 0;
633 if (d.length >= 2)
634 this.y = d[1];
635 else
636 this.y = 0;
637 if (d.length >= 3)
638 this.z = d[2];
639 else
640 this.z = 0;
641 }
642
643
644
645
646
647
648
649 public Velocity(Tuple3d v) {
650 this(v.x, v.y, v.z);
651 }
652
653
654
655
656
657 public static final Pattern velocityPattern = Pattern
658 .compile("\\[([-+]?[0-9]+(\\.[0-9]+){0,1})\\; ([-+]?[0-9]+(\\.[0-9]+){0,1})\\; ([-+]?[0-9]+(\\.[0-9]+){0,1})\\]");
659
660
661
662
663
664
665
666 public Velocity(String string) {
667 Matcher m = velocityPattern.matcher(string);
668 if (m.find()) {
669 String strX = m.group(1);
670 String strY = m.group(3);
671 String strZ = m.group(5);
672 try {
673 this.x = Double.parseDouble(strX);
674 } catch (Exception e) {
675 throw new RuntimeException("String '" + string
676 + "', was not matched as Velocity, because X-coordinate '" + strX + "' is not a number.");
677 }
678 try {
679 this.y = Double.parseDouble(strY);
680 } catch (Exception e) {
681 throw new RuntimeException("String '" + string
682 + "', was not matched as Velocity, because Y-coordinate '" + strY + "' is not a number.");
683 }
684 try {
685 this.z = Double.parseDouble(strZ);
686 } catch (Exception e) {
687 throw new RuntimeException("String '" + string
688 + "', was not matched as Velocity, because Z-coordinate '" + strZ + "' is not a number.");
689 }
690 } else {
691 throw new RuntimeException("String '" + string + "' was not matched as Velocity.");
692 }
693 }
694
695
696
697 @Override
698 public String toString() {
699 return String.format(Locale.ENGLISH, "[%.2f; %.2f; %.2f]", x, y, z);
700 }
701
702 }