View Javadoc

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   * Velocity within the world.
15   *
16   * Direction of the velocity is represented as a vector within the world's
17   * coordinates. Size of the velocity is represented by length of that vector.
18   *
19   * @author Juraj 'Loque' Simlovic
20   */
21  public class Velocity implements ILocomotive, Serializable, Cloneable
22  {
23  	/**
24  	 * Velocity representing NONE.
25  	 */
26  	public static final Velocity NONE = new Velocity(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
27  	
28      static {
29          // register property editor, otherwise this class won't be introspectable
30          PropertyEditorManager.registerEditor(Velocity.class, Velocity.PropertyEditor.class);
31      }
32  
33      /**
34       * Property editor for Velocity. Accepts same format as Location.
35       */
36      public static class PropertyEditor extends PropertyEditorSupport {
37  
38          @Override
39          public String getAsText() {
40              if (getValue() != null) {
41                  return getValue().toString();
42              } else {
43                  return "null";
44              }
45          }
46  
47          @Override
48          public void setAsText(String s) {
49              if ("null".equals(s.trim())) {
50                  setValue(null);
51              } else {
52                  double[] d = Location.PropertyEditor.parseNumberArray(s);
53                  if (d.length != 3) {
54                      throw new IllegalArgumentException();
55                  }
56                  setValue(new Velocity(d));
57              }
58          }
59      }
60      
61      @Override
62      public Velocity clone() {
63      	return new Velocity(this);
64      }
65      
66      public Vector3d asVector3d() {
67      	return new Vector3d(x, y, z);
68      }
69      
70      public Location asLocation() {
71      	return new Location(x,y,z);
72      }
73  
74  	/** X coordinate. */
75  	public double x = 0;
76  	/** Y coordinate. */
77  	public double y = 0;
78  	/** Z coordinate. */
79  	public double z = 0;
80  
81  	/* ********************************************************************** */
82  
83  	/**
84  	 * X coordinate.
85  	 * @return X coordinate.
86  	 */
87  	public double getX()
88  	{
89  		return x;
90  	}
91  
92  	/**
93  	 * Y coordinate.
94  	 * @return Y coordinate.
95  	 */
96  	public double getY()
97  	{
98  		return y;
99  	}
100 
101 	/**
102 	 * Z coordinate.
103 	 * @return Z coordinate.
104 	 */
105 	public double getZ()
106 	{
107 		return z;
108 	}
109 	
110 	/* ********************************************************************** */
111 
112 	/**
113 	 * Sets the X coordinate.
114 	 * @return self.
115 	 */
116 	public Velocity setX(double x)
117 	{
118 		this.x = x;
119 		return this;
120 	}
121 
122 	/**
123 	 * Sets the Y coordinate.
124 	 * @return self.
125 	 */
126 	public Velocity setY(double y)
127 	{
128 		this.y = y;
129 		return this;
130 	}
131 
132 	/**
133 	 * Sets the Z coordinate.
134 	 * @return self.
135 	 */
136 	public Velocity setZ(double z)
137 	{
138 		this.z = z;
139 		return this;
140 	}	
141 
142 	/* ********************************************************************* */
143 
144 	/**
145 	 * Tells, whether the velocity is zero.
146 	 * @return True if the velocity is 0 in all directions; false otherwise.
147 	 */
148 	public boolean isZero ()
149 	{
150 		// test all three elements
151 		return (x == 0) && (y == 0) && (z == 0);
152 	}
153 	
154 	/**
155 	 * Tells, whether the velocity is zero (with tolerance of 'epsilon').
156 	 * @return True if the velocity is 0 in all directions; false otherwise.
157 	 */
158 	public boolean isZero (double epsilon)
159 	{
160 		// test all three elements
161 		return (Math.abs(x) < epsilon) && (Math.abs(y) < epsilon) && (Math.abs(z) < epsilon);
162 	}
163 
164 	/**
165 	 * Tells, whether the velocity is zero in planar coordinates.
166 	 * @return True if the velocity is 0 in planar directions; false otherwise.
167 	 */
168 	public boolean isPlanarZero ()
169 	{
170 		// test two planar elements
171 		return (x == 0) && (y == 0);
172 	}
173 
174 	/**
175 	 * Retreives size of the velocity.
176 	 * @return Size of the velocity.
177 	 */
178 	public double size ()
179 	{
180 		// calculate sqare of the size, then sqrt
181 		return Math.sqrt(x * x + y * y + z * z);
182 	}
183 
184 	/**
185 	 * Retreives squared size of the velocity.
186 	 * @return Size of the velocity to the power of 2.
187 	 */
188 	public double sizeSquare ()
189 	{
190 		// calculate sqare of the size
191 		return x * x + y * y + z * z;
192 	}
193 
194 	/* ********************************************************************* */
195 
196 	/**
197 	 * Retreives normalized vector of the velocity.
198 	 * @return Velocity normalized to the size of 1.
199 	 */
200 	public Velocity normalize ()
201 	{
202 		// calculate reciprocal value of the size of the vector
203 		double d = 1 / Math.sqrt(x * x + y * y + z * z);
204 		// diminish all three directions by the size of the vector
205 		return new Velocity (x * d, y * d, z * d);
206 	}
207 
208 	/**
209 	 * Negates values of all three coordinates.
210 	 * @return Velocity with all three coordinates negated.
211 	 */
212 	public Velocity negate ()
213 	{
214 		// create velocity of negative values
215 		return new Velocity (-x, -y, -z);
216 	}
217 
218 	/**
219 	 * Converts values of all three coordinates to absolute values.
220 	 * @return Velocity with all three coordinates <i>absoluted</i>.
221 	 */
222 	public Velocity absolute ()
223 	{
224 		// create velocity of absoluted values
225 		return new Velocity (Math.abs(x), Math.abs(y), Math.abs(z));
226 	}
227 
228 	/**
229 	 * Scales values of all three coordinates by given multiplier.
230 	 * @param d Scaling multiplier.
231 	 * @return Velocity with all three coordinates negated.
232 	 */
233 	public Velocity scale (double d)
234 	{
235 		// create velocity with scaled values
236 		return new Velocity (x * d, y * d, z * d);
237 	}
238 
239 	/* ********************************************************************* */
240 
241 	/**
242 	 * Computes dot product of this and other given velocity.
243 	 * @param v Second velocity to be computed upon.
244 	 * @return Dot product (scalar product) of the two velocities.
245 	 */
246 	public double dot (Velocity v)
247 	{
248 		// calculate dot product of the vectors
249 		return x * v.x + y * v.y + z * v.z;
250 	}
251 
252 	/**
253 	 * Computes dot product of two given velocities.
254 	 * @param v1 First velocity to be computed upon.
255 	 * @param v2 Second velocity to be computed upon.
256 	 * @return Dot product (scalar product) of the two velocities.
257 	 */
258 	public static double dot (Velocity v1, Velocity v2)
259 	{
260 		// calculate dot product of the vectors
261 		return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
262 	}
263 
264 	/* ********************************************************************* */
265 
266 	/**
267 	 * Computes cross product of this and other given velocity.
268 	 * @param v Second velocity to be computed upon.
269 	 * @return Cross product of the two velocities.
270 	 */
271 	public Velocity cross (Velocity v)
272 	{
273 		// calculate cross product of the vectors
274 		return new Velocity (
275 			y * v.z - z * v.y,
276 			z * v.x - x * v.z,
277 			x * v.y - y * v.x
278 		);
279 	}
280 
281 	/**
282 	 * Computes cross product of two given velocities.
283 	 * @param v1 First velocity to be computed upon.
284 	 * @param v2 Second velocity to be computed upon.
285 	 * @return Cross product of the two velocities.
286 	 */
287 	public static Velocity cross (Velocity v1, Velocity v2)
288 	{
289 		// calculate cross product of the vectors
290 		return new Velocity (
291 			v1.y * v2.z - v1.z * v2.y,
292 			v1.z * v2.x - v1.x * v2.z,
293 			v1.x * v2.y - v1.y * v2.x
294 		);
295 	}
296 
297 	/* ********************************************************************* */
298 
299 	/**
300 	 * Retreives sum of this velocity and given velocity.
301 	 * @param v Velocity to by added to this velocity.
302 	 * @return Sum of the two velocities.
303 	 */
304 	public Velocity add (Velocity v)
305 	{
306 		// create sum of the velocities
307 		return new Velocity (x + v.x, y + v.y, z + v.z);
308 	}
309 
310 	/**
311 	 * Retreives sum of two given velocities.
312 	 * @param v1 First velocity to by summed.
313 	 * @param v2 Second velocity to by summed.
314 	 * @return Sum of the two velocities.
315 	 */
316 	public static Velocity add (Velocity v1, Velocity v2)
317 	{
318 		// create sum of the velocities
319 		return new Velocity (v1.x + v2.x, v1.y + v2.y, v1.z + v2.z);
320 	}
321 
322 	/**
323 	 * Retreives subtraction of given velocity from this velocity.
324 	 * @param v Velocity to be subtracted.
325 	 * @return Subtraction of the two velocities.
326 	 */
327 	public Velocity sub (Velocity v)
328 	{
329 		// create substraction of the velocities
330 		return new Velocity (x - v.x, y - v.y, z - v.z);
331 	}
332 
333 	/**
334 	 * Retreives subtraction of two given velocities.
335 	 * @param v1 Velocity to be subtracted from.
336 	 * @param v2 Velocity to be subtracted.
337 	 * @return Subtraction of the two velocities.
338 	 */
339 	public static Velocity sub (Velocity v1, Velocity v2)
340 	{
341 		// create substraction of the velocities
342 		return new Velocity (v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
343 	}
344 
345 	/* ********************************************************************* */
346 
347 	/**
348 	 * Linearly interpolates between this velocity and given velocity.
349 	 * @param v Velocity to be interpolated to.
350 	 * @param d Interpolation parameter.
351 	 * @return Linear interpolation between the two velocities.
352 	 */
353 	public Velocity interpolate(Velocity v, double d)
354 	{
355 		// from the other side
356 		double d1 = 1.0D - d;
357 		// create interpolation of the velocities
358 		return new Velocity (d1 * x + d * v.x, d1 * y + d * v.y, d1 * z + d * v.z);
359 	}
360 
361 	/**
362 	 * Linearly interpolates between two given velocities.
363 	 * @param v1 Velocity to be interpolated from.
364 	 * @param v2 Velocity to be interpolated to.
365 	 * @param d Interpolation parameter.
366 	 * @return Linear interpolation between the two velocities.
367 	 */
368 	public static Velocity interpolate(Velocity v1, Velocity v2, double d)
369 	{
370 		// from the other side
371 		double d1 = 1.0D - d;
372 		// create interpolation of the velocities
373 		return new Velocity (d1 * v1.x + d * v2.x, d1 * v1.y + d * v2.y, d1 * v1.z + d * v2.z);
374 	}
375 
376 	/* ********************************************************************* */
377 
378 	/**
379 	 * Tells, whether this velocity equals to given velocity.
380 	 * @param v Velocity to be compared with.
381 	 * @return True, if the velocities have the same values of all three
382 	 * corresponding coordinates.
383 	 */
384 	public boolean equals (Velocity v)
385 	{
386 		// test all three elements
387 		return (x == v.x) && (y == v.y) && (z == v.z);
388 	}
389 
390 	/**
391 	 * Tells, whether two given velocities equal.
392 	 * @param v1 First velocity to comapre.
393 	 * @param v2 Second velocity to comapre.
394 	 * @return True, if the velocities have the same values of all three
395 	 * corresponding coordinates.
396 	 */
397 	public static boolean equal (Velocity v1, Velocity v2)
398 	{
399 		// test all three elements
400 		return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z);
401 	}
402 
403 	/**
404 	 * Tells, whether the distance between coordinates of this velocity
405 	 * and given velocity is less than or equal to the given epsilon.
406 	 * @param v Velocity to comapre with.
407 	 * @param epsilon Epsilon to compare with.
408 	 * @return True, if the distance between the velocities is less than the
409 	 * epsilon, false otherwise.
410 	 */
411 	public boolean equals (Velocity v, double epsilon)
412 	{
413 		double d;
414 
415 		// x axes distance
416 		d = x - v.x;
417 		if((d >= 0 ? d : -d) > epsilon)
418 			return false;
419 
420 		// y axes distance
421 		d = y - v.y;
422 		if((d >= 0.0D ? d : -d) > epsilon)
423 			return false;
424 
425 		// z axes distance
426 		d = z - v.z;
427 		if((d >= 0.0D ? d : -d) > epsilon)
428 			return false;
429 
430 		// aye, aye, sir..
431 		return true;
432 	}
433 
434 	/**
435 	 * Tells, whether the distance between coordinates of two given velocities
436 	 * is less than or equal to the given epsilon.
437 	 * @param v1 First velocity to comapre.
438 	 * @param v2 Second velocity to comapre.
439 	 * @param epsilon Epsilon to compare with.
440 	 * @return True, if the distance between the velocities is less than the
441 	 * epsilon, false otherwise.
442 	 */
443 	public static boolean equal (Velocity v1, Velocity v2, double epsilon)
444 	{
445 		double d;
446 
447 		// x axes distance
448 		d = v1.x - v2.x;
449 		if((d >= 0 ? d : -d) > epsilon)
450 			return false;
451 
452 		// y axes distance
453 		d = v1.y - v2.y;
454 		if((d >= 0.0D ? d : -d) > epsilon)
455 			return false;
456 
457 		// z axes distance
458 		d = v1.z - v2.z;
459 		if((d >= 0.0D ? d : -d) > epsilon)
460 			return false;
461 
462 		// aye, aye, sir..
463 		return true;
464 	}
465 
466 	/* ********************************************************************* */
467 
468 	/**
469 	 * Projects the velocity into the (x, y) plane, i.e. removes z coordinate.
470 	 * @return Aligned velocity, with z coordinate set to zero.
471 	 */
472 	public Velocity align ()
473 	{
474 		// create aligned velocity
475 		return new Velocity (x, y, 0);
476 	}
477 
478 	/**
479 	 * Computes sideways velocity, i.e. orthogonal velocity to projection of
480 	 * this velocity to (x, y) plane.
481 	 *
482 	 * <p>Note: Ignores the z coordinate whatsoever, which is the same as
483 	 * projecting the velocity to the (x, y) plane. Calculates orthogonal
484 	 * vector to this projection. Returns vector (y, -x, 0).
485 	 *
486 	 * @return Aligned velocity, with z coordinate set to zero.
487 	 */
488 	public Velocity sideways ()
489 	{
490 		// create aligned velocity
491 		return new Velocity (y, -x, 0);
492 	}
493 
494 	/* ********************************************************************* */
495 
496 	/**
497 	 * Retreives the velocity itself to implement {@link ILocomotive}.
498 	 * @return The velocity itself (note: does not create a copy).
499 	 */
500 	@Override
501 	public Velocity getVelocity()
502 	{
503 		return this;
504 	}
505 
506 	/**
507 	 * Retreives javax.vecmath.Vector3d representation of the velocity.
508 	 * @return javax.vecmath.Vector3d representation with x, y and z values set.
509 	 */
510 	public Vector3d getVector3d()
511 	{
512 		return new Vector3d (x, y, z);
513 	}
514 
515 	/* ********************************************************************** */
516 
517 	/**
518 	 * Creates velocity with all values set to zeroes.
519 	 */
520 	public Velocity()
521 	{
522 	}
523 
524 	/**
525 	 * Creates velocity same as the the passed one.
526 	 * @param velocity original velocity that will be copied
527 	 */
528 	public Velocity(Velocity velocity) {
529 		this.x = velocity.getX();
530 		this.y = velocity.getY();
531 		this.z = velocity.getZ();
532 	}
533 
534 	/**
535 	 * Creates velocity with specified coordinates.
536 	 * @param x X coordinate.
537 	 * @param y Y coordinate.
538 	 * @param z Z coordinate.
539 	 */
540 	public Velocity(double x, double y, double z)
541 	{
542 		this.x = x;
543 		this.y = y;
544 		this.z = z;
545 	}
546 
547 	/**
548 	 * Creates velocity with specified planar coordinates. Sets z to zero.
549 	 * @param x X coordinate.
550 	 * @param y Y coordinate.
551 	 */
552 	public Velocity(double x, double y)
553 	{
554 		this.x = x;
555 		this.y = y;
556 	}
557 
558 	/**
559 	 * Creates velocity from array of three doubles.
560 	 * Sets x = d[0], y = d[1] and z = d[2].
561 	 * @param d Array of (at least) three doubles to be used for creation.
562 	 */
563 	public Velocity(double d[])
564 	{
565 		this.x = d[0];
566 		this.y = d[1];
567 		this.z = d[2];
568 	}
569 
570 	/**
571 	 * Creates velocity from specified 3D vector.
572 	 * @param v Vector in space to be used for creation.
573 	 */
574 	public Velocity(Tuple3d v)
575 	{
576 		this.x = v.x;
577 		this.y = v.y;
578 		this.z = v.z;
579 	}
580 	
581 	/**
582 	 * Pattern used to parse {@link Velocity#toString()} in {@link Velocity#Velocity(String)}.
583 	 */
584 	public static final Pattern velocityPattern = Pattern.compile("\\[([-+]?[0-9]+(\\.[0-9]+){0,1})\\; ([-+]?[0-9]+(\\.[0-9]+){0,1})\\; ([-+]?[0-9]+(\\.[0-9]+){0,1})\\]");
585 	
586 	/**
587 	 * Parses the velocity from the "string" generated by {@link Velocity#toString()}. If it fails,
588 	 * it throws RuntimeException.
589 	 * 
590 	 * @param string
591 	 */
592 	public Velocity(String string) {
593 		Matcher m = velocityPattern.matcher(string);
594 		if (m.find()) {
595 			String strX = m.group(1);
596 			String strY = m.group(3);
597 			String strZ = m.group(5);
598 			try {
599 				this.x = Double.parseDouble(strX);
600 			} catch (Exception e) {
601 				throw new RuntimeException("String '" + string + "', was not matched as Velocity, because X-coordinate '" + strX + "' is not a number.");
602 			}
603 			try {
604 				this.y = Double.parseDouble(strY);
605 			} catch (Exception e) {
606 				throw new RuntimeException("String '" + string + "', was not matched as Velocity, because Y-coordinate '" + strY + "' is not a number.");
607 			}
608 			try {
609 				this.z = Double.parseDouble(strZ);
610 			} catch (Exception e) {
611 				throw new RuntimeException("String '" + string + "', was not matched as Velocity, because Z-coordinate '" + strZ + "' is not a number.");
612 			}
613 		} else {
614 			throw new RuntimeException("String '" + string +"' was not matched as Velocity.");
615 		}
616 	}
617 
618 	/* ********************************************************************** */
619 
620 	@Override
621 	public String toString()
622 	{
623 		return String.format (Locale.ENGLISH, "[%.2f; %.2f; %.2f]", x, y, z);
624 	}
625 
626 }