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.Collection;
7   import java.util.Iterator;
8   import java.util.Locale;
9   import java.util.StringTokenizer;
10  import java.util.regex.Matcher;
11  import java.util.regex.Pattern;
12  
13  import javax.vecmath.Matrix3d;
14  import javax.vecmath.Point3d;
15  import javax.vecmath.Tuple3d;
16  import javax.vecmath.Vector3d;
17  
18  import math.geom3d.Point3D;
19  
20  /**
21   * Location within the world.
22   * 
23   * Location is represented as a point within the world's coordinates.
24   * 
25   * @author Juraj 'Loque' Simlovic
26   * @author Radek 'Black_Hand' Pibil
27   */
28  public class Location implements ILocated, Serializable, Cloneable {
29  
30  	/**
31  	 * Location representing NONE.
32  	 */
33  	public static final Location NONE = new Location(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
34  	
35  	/**
36  	 * This here is for StoryFactory compatibility reasons. Can be removed in
37  	 * 2012.
38  	 */
39  	static final long serialVersionUID = -7001866845605943889L;
40  
41  	/**
42  	 * We have to register PropertyEditor for Location, without it, Location
43  	 * won't be introspectable.
44  	 */
45  	static {
46  		PropertyEditorManager.registerEditor(Location.class,
47  				Location.PropertyEditor.class);
48  	}
49  
50  	/**
51  	 * PropertyEditor for class Location.
52  	 */
53  	public static class PropertyEditor extends PropertyEditorSupport {
54  
55  		@Override
56  		public String getAsText() {
57  			if (getValue() != null) {
58  				return getValue().toString();
59  			} else {
60  				return "null";
61  			}
62  		}
63  
64  		@Override
65  		public void setAsText(String s) {
66  			if ("null".equals(s.trim())) {
67  				setValue(null);
68  			} else {
69  				double[] d = Location.PropertyEditor.parseNumberArray(s);
70  				if (d.length != 3) {
71  					throw new IllegalArgumentException();
72  				}
73  				setValue(new Location(d));
74  			}
75  		}
76  
77  		public static double[] parseNumberArray(String s) {
78  			s = s.trim();
79  			// if string has brackets, remove them
80  			if ((s.startsWith("[") && s.endsWith("]"))
81  					|| (s.startsWith("(") && s.endsWith(")"))) {
82  				s = s.substring(1, s.length() - 1);
83  			}
84  			// now we expect num , num, num
85  			StringTokenizer st = new StringTokenizer(s, ";");
86  
87  			// try to parse numbers and set the new value
88  			try {
89  				double[] d = new double[st.countTokens()];
90  				for (int i = 0; i < d.length; ++i) {
91  					d[i] = Double.parseDouble(st.nextToken());
92  				}
93  				return d;
94  			} catch (NumberFormatException ex) {
95  				throw new IllegalArgumentException(ex);
96  			}
97  		}
98  
99  		@Override
100 		public boolean supportsCustomEditor() {
101 			return false;
102 		}
103 	}
104 
105 	@Override
106 	public Location clone() {
107 		return new Location(this);
108 	}
109 
110 	public Vector3d asVector3d() {
111 		return new Vector3d(x, y, z);
112 	}
113 
114 	public Point3d asPoint3d() {
115 		return new Point3d(x, y, z);
116 	}
117 
118 	public Point3D asPoint3D() {
119 		return new Point3D(x, y, z);
120 	}
121 
122 	/** X coordinate. */
123 	public double x = 0;
124 	/** Y coordinate. */
125 	public double y = 0;
126 	/** Z coordinate. */
127 	public double z = 0;
128 
129 	/* ********************************************************************** */
130 
131 	/**
132 	 * X coordinate.
133 	 * 
134 	 * @return X coordinate.
135 	 */
136 	public double getX() {
137 		return x;
138 	}
139 
140 	/**
141 	 * Y coordinate.
142 	 * 
143 	 * @return Y coordinate.
144 	 */
145 	public double getY() {
146 		return y;
147 	}
148 
149 	/**
150 	 * Z coordinate.
151 	 * 
152 	 * @return Z coordinate.
153 	 */
154 	public double getZ() {
155 		return z;
156 	}
157 
158 	/* ********************************************************************** */
159 
160 	/**
161 	 * Retreives sum of this location and given location.
162 	 * 
163 	 * @param l
164 	 *            Location to be added to this location.
165 	 * @return Sum of the two locations.
166 	 */
167 	public Location add(Location l) {
168 		// create sum of the locations
169 		return new Location(x + l.x, y + l.y, z + l.z);
170 	}
171 
172 	/**
173 	 * Retreives sum of two given locations.
174 	 * 
175 	 * @param l1
176 	 *            First location to be summed.
177 	 * @param l2
178 	 *            Second location to be summed.
179 	 * @return Sum of the two locations.
180 	 */
181 	public static Location add(Location l1, Location l2) {
182 		// create sum of the locations
183 		return new Location(l1.x + l2.x, l1.y + l2.y, l1.z + l2.z);
184 	}
185 
186 	/**
187 	 * Retreives subtraction of given location from this location.
188 	 * 
189 	 * @param l
190 	 *            Location to be subtracted.
191 	 * @return Subtraction of the two locations.
192 	 */
193 	public Location sub(Location l) {
194 		// create substraction of the locations
195 		return new Location(x - l.x, y - l.y, z - l.z);
196 	}
197 
198 	/**
199 	 * Retreives subtraction of two given locations.
200 	 * 
201 	 * @param l1
202 	 *            Location to be subtracted from.
203 	 * @param l2
204 	 *            Location to be subtracted.
205 	 * @return Subtraction of the two locations.
206 	 */
207 	public static Location sub(Location l1, Location l2) {
208 		// create substraction of the locations
209 		return new Location(l1.x - l2.x, l1.y - l2.y, l1.z - l2.z);
210 	}
211 
212 	/* ********************************************************************* */
213 
214 	/**
215 	 * Adds given velocity to this location.
216 	 * 
217 	 * @param v
218 	 *            Velocity to be added to this location.
219 	 * @return Sum of the location and velocity.
220 	 */
221 	public Location add(Velocity v) {
222 		// create sum of the locations
223 		return new Location(x + v.x, y + v.y, z + v.z);
224 	}
225 
226 	/**
227 	 * Adds given velocity to given location.
228 	 * 
229 	 * @param l
230 	 *            Location to be summed.
231 	 * @param v
232 	 *            Velocity to be summed.
233 	 * @return Sum of the location and velocity.
234 	 */
235 	public static Location add(Location l, Velocity v) {
236 		// create sum of the locations
237 		return new Location(l.x + v.x, l.y + v.y, l.z + v.z);
238 	}
239 
240 	/**
241 	 * Subtracts given velocity from this location.
242 	 * 
243 	 * @param v
244 	 *            Velocity to be subtracted.
245 	 * @return Subtraction of the velocity from the location.
246 	 */
247 	public Location sub(Velocity v) {
248 		// create substraction of the locations
249 		return new Location(x - v.x, y - v.y, z - v.z);
250 	}
251 
252 	/**
253 	 * Subtracts given velocity from given location.
254 	 * 
255 	 * @param l
256 	 *            Location to be subtracted from.
257 	 * @param v
258 	 *            Velocity to be subtracted.
259 	 * @return Subtraction of the velocity from the location.
260 	 */
261 	public static Location sub(Location l, Velocity v) {
262 		// create substraction of the locations
263 		return new Location(l.x - v.x, l.y - v.y, l.z - v.z);
264 	}
265 
266 	/* ********************************************************************* */
267 
268 	/**
269 	 * Scales values of all three coordinates by given multiplier.
270 	 * 
271 	 * @param d
272 	 *            Scaling multiplier.
273 	 * @return Location with all three coordinates negated.
274 	 */
275 	public Location scale(double d) {
276 		// create location with scaled values
277 		return new Location(x * d, y * d, z * d);
278 	}
279 
280 	/* ********************************************************************* */
281 
282 	/**
283 	 * Lineary interpolates between this location and given location.
284 	 * 
285 	 * @param l
286 	 *            Location to be interpolated to.
287 	 * @param d
288 	 *            Interpolation parameter.
289 	 * @return Linear interpolation between the two locations.
290 	 */
291 	public Location interpolate(Location l, double d) {
292 		// from the other side
293 		double d1 = 1.0D - d;
294 		// create interpolation of the locations
295 		return new Location(d1 * x + d * l.x, d1 * y + d * l.y, d1 * z + d
296 				* l.z);
297 	}
298 
299 	/**
300 	 * Linearly interpolates between two given locations.
301 	 * 
302 	 * @param l1
303 	 *            Location to be interpolated from.
304 	 * @param l2
305 	 *            Location to be interpolated to.
306 	 * @param d
307 	 *            Interpolation parameter.
308 	 * @return Linear interpolation between the two locations.
309 	 */
310 	public static Location interpolate(Location l1, Location l2, double d) {
311 		// from the other side
312 		double d1 = 1.0D - d;
313 		// create interpolation of the locations
314 		return new Location(d1 * l1.x + d * l2.x, d1 * l1.y + d * l2.y, d1
315 				* l1.z + d * l2.z);
316 	}
317 
318 	/* ********************************************************************** */
319 
320 	/**
321 	 * Tells, whether this location equals to given location.
322 	 * 
323 	 * @param v
324 	 *            Location to be compared with.
325 	 * @return True, if the locations have the same values of all three
326 	 *         corresponding coordinates.
327 	 */
328 	public boolean equals(Location v) {
329 		if (v == null)
330 			return false;
331 		// test all three elements
332 		return (x == v.x) && (y == v.y) && (z == v.z);
333 	}
334 
335 	/**
336 	 * Tells, whether two given locations equal.
337 	 * 
338 	 * @param l1
339 	 *            First location to comapre.
340 	 * @param l2
341 	 *            Second location to comapre.
342 	 * @return True, if the locations have the same values of all three
343 	 *         corresponding coordinates.
344 	 */
345 	public static boolean equal(Location l1, Location l2) {
346 		// test all three elements
347 		return (l1.x == l2.x) && (l1.y == l2.y) && (l1.z == l2.z);
348 	}
349 
350 	/**
351 	 * Tells, whether the distance between coordinates of this location and
352 	 * given location is less than or equal to the given epsilon.
353 	 * 
354 	 * @param l
355 	 *            Location to comapre with.
356 	 * @param epsilon
357 	 *            Epsilon to compare with.
358 	 * @return True, if the distance between the locations is less than the
359 	 *         epsilon, false otherwise.
360 	 */
361 	public boolean equals(Location l, double epsilon) {
362 		double d;
363 
364 		// x axes distance
365 		d = x - l.x;
366 		if ((d >= 0 ? d : -d) > epsilon)
367 			return false;
368 
369 		// y axes distance
370 		d = y - l.y;
371 		if ((d >= 0.0D ? d : -d) > epsilon)
372 			return false;
373 
374 		// z axes distance
375 		d = z - l.z;
376 		if ((d >= 0.0D ? d : -d) > epsilon)
377 			return false;
378 
379 		// aye, aye, sir..
380 		return true;
381 	}
382 
383 	/**
384 	 * Tells, whether the distance between coordinates of two given locations is
385 	 * less than or equal to the given epsilon.
386 	 * 
387 	 * @param l1
388 	 *            First location to comapre.
389 	 * @param l2
390 	 *            Second location to comapre.
391 	 * @param epsilon
392 	 *            Epsilon to compare with.
393 	 * @return True, if the distance between the locations is less than the
394 	 *         epsilon, false otherwise.
395 	 */
396 	public static boolean equal(Location l1, Location l2, double epsilon) {
397 		double d;
398 
399 		// x axes distance
400 		d = l1.x - l2.x;
401 		if ((d >= 0 ? d : -d) > epsilon)
402 			return false;
403 
404 		// y axes distance
405 		d = l1.y - l2.y;
406 		if ((d >= 0.0D ? d : -d) > epsilon)
407 			return false;
408 
409 		// z axes distance
410 		d = l1.z - l2.z;
411 		if ((d >= 0.0D ? d : -d) > epsilon)
412 			return false;
413 
414 		// aye, aye, sir..
415 		return true;
416 	}
417 
418 	/* ********************************************************************** */
419 
420 	/**
421 	 * Calculates average of all 'locations'. If locations.size() == 0, returns
422 	 * null.
423 	 * 
424 	 * @param locations
425 	 * @return average location
426 	 */
427 	public static Location getAverage(Collection<Location> locations) {
428 		if (locations.size() == 0)
429 			return null;
430 		Iterator<Location> iter = locations.iterator();
431 		Location result = new Location(iter.next());
432 		while (iter.hasNext()) {
433 			result.add(iter.next());
434 		}
435 		return result.scale(1 / locations.size());
436 	}
437 
438 	/* ********************************************************************** */
439 
440 	/**
441 	 * Calculates the distance between this and given location.
442 	 * 
443 	 * @param l
444 	 *            Location to be calculated the distance to.
445 	 * @return Euclidean distance between the two locations.
446 	 */
447 	public double getDistance(Location l) {
448 		double dx = l.x - x;
449 		double dy = l.y - y;
450 		double dz = l.z - z;
451 		return Math.sqrt(dx * dx + dy * dy + dz * dz);
452 	}
453 
454 	/**
455 	 * Calculates the distance between this and given location (ignoring 'z'
456 	 * coordinate).
457 	 * 
458 	 * @param l
459 	 *            Location to be calculated the distance to.
460 	 * @return Euclidean distance between the two locations.
461 	 */
462 	public double getDistance2D(Location l) {
463 		double dx = l.x - x;
464 		double dy = l.y - y;
465 		return Math.sqrt(dx * dx + dy * dy);
466 	}
467 
468 	/**
469 	 * Calculates the distance between two given locations.
470 	 * 
471 	 * @param l1
472 	 *            Location to be calculated the distance from.
473 	 * @param l2
474 	 *            Location to be calculated the distance to.
475 	 * @return Euclidean distance between the two locations.
476 	 */
477 	public static double getDistance(Location l1, Location l2) {
478 		double dx = l2.x - l1.x;
479 		double dy = l2.y - l1.y;
480 		double dz = l2.z - l1.z;
481 		return Math.sqrt(dx * dx + dy * dy + dz * dz);
482 	}
483 
484 	/**
485 	 * Returns difference between z-coords (this.z - location.z).
486 	 * 
487 	 * @param location
488 	 * @return z-difference
489 	 */
490 	public double getDistanceZ(Location location) {
491 		return z - location.z;
492 	}
493 
494 	/**
495 	 * Calculates the distance between two given locations (ignoring 'z'
496 	 * coordinate).
497 	 * 
498 	 * @param l1
499 	 *            Location to be calculated the distance from.
500 	 * @param l2
501 	 *            Location to be calculated the distance to.
502 	 * @return Euclidean distance between the two locations.
503 	 */
504 	public static double getDistance2D(Location l1, Location l2) {
505 		double dx = l2.x - l1.x;
506 		double dy = l2.y - l1.y;
507 		return Math.sqrt(dx * dx + dy * dy);
508 	}
509 
510 	/**
511 	 * Calculates the square of the distance between this and given location.
512 	 * 
513 	 * @param l
514 	 *            Location to be calculated the distance to.
515 	 * @return Square of the euclidean distance between the two locations.
516 	 */
517 	public double getDistanceSquare(Location l) {
518 		double dx = l.x - x;
519 		double dy = l.y - y;
520 		double dz = l.z - z;
521 		return dx * dx + dy * dy + dz * dz;
522 	}
523 
524 	/**
525 	 * Calculates the square of the distance between two given locations.
526 	 * 
527 	 * @param l1
528 	 *            Location to be calculated the distance from.
529 	 * @param l2
530 	 *            Location to be calculated the distance to.
531 	 * @return Square of the euclidean distance between the two locations.
532 	 */
533 	public static double getDistanceSquare(Location l1, Location l2) {
534 		double dx = l2.x - l1.x;
535 		double dy = l2.y - l1.y;
536 		double dz = l2.z - l1.z;
537 		return dx * dx + dy * dy + dz * dz;
538 	}
539 
540 	/**
541 	 * Calculates the Manhattan distance between this and given location.
542 	 * 
543 	 * @param l
544 	 *            Location to be calculated the distance to.
545 	 * @return Manhattan (i.e. 1-norm) distance between the two locations.
546 	 */
547 	public double getDistanceL1(Location l) {
548 		double dx = Math.abs(l.x - x);
549 		double dy = Math.abs(l.y - y);
550 		double dz = Math.abs(l.z - z);
551 		return dx + dy + dz;
552 	}
553 
554 	/**
555 	 * Calculates the Manhattan distance between two given locations.
556 	 * 
557 	 * @param l1
558 	 *            Location to be calculated the distance from.
559 	 * @param l2
560 	 *            Location to be calculated the distance to.
561 	 * @return Manhattan (i.e. 1-norm) distance between the two locations.
562 	 */
563 	public static double getDistanceL1(Location l1, Location l2) {
564 		double dx = Math.abs(l2.x - l1.x);
565 		double dy = Math.abs(l2.y - l1.y);
566 		double dz = Math.abs(l2.z - l1.z);
567 		return dx + dy + dz;
568 	}
569 
570 	/**
571 	 * Calculates the Chebyshev distance between this and given location.
572 	 * 
573 	 * @param l
574 	 *            Location to be calculated the distance to.
575 	 * @return Chebyshev (i.e. infinity-norm) distance between the two
576 	 *         locations.
577 	 */
578 	public double getDistanceLinf(Location l) {
579 		double dx = Math.abs(l.x - x);
580 		double dy = Math.abs(l.y - y);
581 		double dz = Math.abs(l.z - z);
582 		return Math.max(Math.max(dx, dy), dz);
583 	}
584 
585 	/**
586 	 * Calculates the Chebyshev distance between two given locations.
587 	 * 
588 	 * @param l1
589 	 *            Location to be calculated the distance from.
590 	 * @param l2
591 	 *            Location to be calculated the distance to.
592 	 * @return Chebyshev (i.e. infinity-norm) distance between the two
593 	 *         locations.
594 	 */
595 	public static double getDistanceLinf(Location l1, Location l2) {
596 		double dx = Math.abs(l2.x - l1.x);
597 		double dy = Math.abs(l2.y - l1.y);
598 		double dz = Math.abs(l2.z - l1.z);
599 		return Math.max(Math.max(dx, dy), dz);
600 	}
601 
602 	/**
603 	 * Calculates the distance between this and given location after being
604 	 * projected to the (x,y) plane.
605 	 * 
606 	 * @param l
607 	 *            Location to be calculated the distance to.
608 	 * @return Plane-projected distance between the two locations.
609 	 */
610 	public double getDistancePlane(Location l) {
611 		double dx = l.x - x;
612 		double dy = l.y - y;
613 		return Math.sqrt(dx * dx + dy * dy);
614 	}
615 
616 	/**
617 	 * Calculates the distance between two given locations after being projected
618 	 * to the (x,y) plane.
619 	 * 
620 	 * @param l1
621 	 *            Location to be calculated the distance from.
622 	 * @param l2
623 	 *            Location to be calculated the distance to.
624 	 * @return Plane-projected distance between the two locations.
625 	 */
626 	public static double getDistancePlane(Location l1, Location l2) {
627 		double dx = l2.x - l1.x;
628 		double dy = l2.y - l1.y;
629 		return Math.sqrt(dx * dx + dy * dy);
630 	}
631 
632 	/* ********************************************************************** */
633 
634 	/**
635 	 * Retreives the location itself to implement {@link ILocated}.
636 	 * 
637 	 * @return The location itself (note: does not create a copy).
638 	 */
639 	@Override
640 	public Location getLocation() {
641 		return this;
642 	}
643 
644 	/**
645 	 * Retreives javax.vecmath.Point3d representation of the location.
646 	 * 
647 	 * @return javax.vecmath.Point3d representation with x, y and z values set.
648 	 */
649 	public Point3d getPoint3d() {
650 		return new Point3d(x, y, z);
651 	}
652 
653 	/* ********************************************************************** */
654 
655 	/**
656 	 * Creates location with all values set to zeroes.
657 	 */
658 	public Location() {
659 	}
660 
661 	/**
662 	 * Creates location with specified coordinates.
663 	 * 
664 	 * @param x
665 	 *            X coordinate.
666 	 * @param y
667 	 *            Y coordinate.
668 	 * @param z
669 	 *            Z coordinate.
670 	 */
671 	public Location(double x, double y, double z) {
672 		this.x = x;
673 		this.y = y;
674 		this.z = z;
675 	}
676 
677 	/**
678 	 * Creates location with specified planar coordinates. Sets z to zero.
679 	 * 
680 	 * @param x
681 	 *            X coordinate.
682 	 * @param y
683 	 *            Y coordinate.
684 	 */
685 	public Location(double x, double y) {
686 		this.x = x;
687 		this.y = y;
688 	}
689 
690 	/**
691 	 * Copy constructor
692 	 * 
693 	 * @param source
694 	 *            Location to copy
695 	 */
696 	public Location(Location source) {
697 		this.x = source.getX();
698 		this.y = source.getY();
699 		this.z = source.getZ();
700 	}
701 
702 	/**
703 	 * Pattern used to parse {@link Location#toString()} in
704 	 * {@link Location#Location(String)}.
705 	 */
706 	public static final Pattern locationPattern = Pattern
707 			.compile("\\[([-+]?[0-9]+(\\.[0-9]+){0,1})\\; ([-+]?[0-9]+(\\.[0-9]+){0,1})\\; ([-+]?[0-9]+(\\.[0-9]+){0,1})\\]");
708 	
709 	/**
710 	 * Zero delta for {@link Location#equals(Location)}.
711 	 */
712 	public static final double DISTANCE_ZERO = 0.000000001;
713 
714 	/**
715 	 * Parses the location from the "string" generated by
716 	 * {@link Location#toString()}. If it fails, it throws RuntimeException.
717 	 * 
718 	 * @param string
719 	 */
720 	public Location(String string) {
721 		Matcher m = locationPattern.matcher(string);
722 		if (m.find()) {
723 			String strX = m.group(1);
724 			String strY = m.group(3);
725 			String strZ = m.group(5);
726 			try {
727 				this.x = Double.parseDouble(strX);
728 			} catch (Exception e) {
729 				throw new RuntimeException(
730 						"String '"
731 								+ string
732 								+ "', was not matched as Location, because X-coordinate '"
733 								+ strX + "' is not a number.");
734 			}
735 			try {
736 				this.y = Double.parseDouble(strY);
737 			} catch (Exception e) {
738 				throw new RuntimeException(
739 						"String '"
740 								+ string
741 								+ "', was not matched as Location, because Y-coordinate '"
742 								+ strY + "' is not a number.");
743 			}
744 			try {
745 				this.z = Double.parseDouble(strZ);
746 			} catch (Exception e) {
747 				throw new RuntimeException(
748 						"String '"
749 								+ string
750 								+ "', was not matched as Location, because Z-coordinate '"
751 								+ strZ + "' is not a number.");
752 			}
753 		} else {
754 			throw new RuntimeException("String '" + string
755 					+ "' was not matched as Location.");
756 		}
757 	}
758 
759 	/**
760 	 * Creates location from array of three doubles. Sets x = d[0], y = d[1] and
761 	 * z = d[2].
762 	 * 
763 	 * @param d
764 	 *            Array of doubles to be used for creation.
765 	 */
766 	public Location(double d[]) {
767 		if (d.length >= 1)
768 			this.x = d[0];
769 		if (d.length >= 2)
770 			this.y = d[1];
771 		if (d.length >= 3)
772 			this.z = d[2];
773 	}
774 
775 	/**
776 	 * Creates location from array of three doubles. Sets x = f[0], y = f[1] and
777 	 * z = f[2].
778 	 * 
779 	 * @param f
780 	 *            Array of to be used for creation.
781 	 */
782 	public Location(float f[]) {
783 		if (f.length >= 1)
784 			this.x = f[0];
785 		if (f.length >= 2)
786 			this.y = f[1];
787 		if (f.length >= 3)
788 			this.z = f[2];
789 	}
790 
791 	/**
792 	 * Creates location from specified 3D point.
793 	 * 
794 	 * @param p
795 	 *            Point in space to be used for creation.
796 	 */
797 	public Location(Tuple3d p) {
798 		this.x = p.x;
799 		this.y = p.y;
800 		this.z = p.z;
801 	}
802 
803 	/**
804 	 * Calculates dot product of this Location and Location b
805 	 * 
806 	 * @param b
807 	 *            Location to dot with
808 	 * @return dot product of this and b
809 	 */
810 	public double dot(Location b) {
811 		return x * b.getX() + y * b.getY() + z * b.getZ();
812 	}
813 
814 	/**
815 	 * Calculates dot product of this Location and Location b in 2D (x,y coord
816 	 * only)
817 	 * 
818 	 * @param b
819 	 *            Location to dot with
820 	 * @return dot product of this and b
821 	 */
822 	public double dot2D(Location b) {
823 		return x * b.getX() + y * b.getY();
824 	}
825 
826 	/**
827 	 * Calculates cross product of this Location and Lcoations b
828 	 * 
829 	 * @param b
830 	 *            Location to cross with
831 	 * @return cross product of this and b
832 	 */
833 	public Location cross(Location b) {
834 		return new Location(y * b.getZ() - z * b.getY(), z * b.getX() - x
835 				* b.getZ(), x * b.getY() - y * b.getX());
836 	}
837 
838 	/**
839 	 * Converts Location into Rotation. Since location is only a single vector,
840 	 * roll is ommited.
841 	 * 
842 	 * @param order
843 	 *            tells resulting rotation, which rotation order should it
844 	 *            represent
845 	 * @return resulting rotation
846 	 */
847 	public Rotation getRotation(Rotation.Order order) {
848 		Location this_normalized = getNormalized();
849 		double yaw = 0d, pitch = 0d;
850 		switch (order) {
851 		case YAW_PITCH_ROLL:
852 		case ROLL_YAW_PITCH:
853 		case YAW_ROLL_PITCH:
854 			yaw = Math.atan2(this_normalized.getY(), Math.sqrt(1
855 					- this_normalized.getY() * this_normalized.getY()));
856 
857 			pitch = Math.atan2(this_normalized.getZ(), this_normalized.getX());
858 			break;
859 		case PITCH_YAW_ROLL:
860 		case PITCH_ROLL_YAW:
861 		case ROLL_PITCH_YAW:
862 			pitch = Math.atan2(Math.sqrt(1 - this_normalized.getZ()
863 					* this_normalized.getZ()), this_normalized.getZ());
864 			yaw = Math.atan2(this_normalized.getX(), this_normalized.getY());
865 			break;
866 		}
867 		return new Rotation(pitch / Math.PI * 32768 - 1, yaw / Math.PI * 32768
868 				- 1, 0);
869 	}
870 
871 	/**
872 	 * WIP not completed yet. Use only in case roll yaw pitch order is used.
873 	 * Converts this location into rotation required to be applied on (1,0,0) in
874 	 * order achieve this location. Difference from getRotation is that in this
875 	 * case, quaternion like rotation chaining is achieved. That means that if
876 	 * you take rotation (x, y, z) then result would be same as applying
877 	 * rotation (x, 0, 0) on (1, 0, 0) - identity - then (0, y, 0) on the
878 	 * result, but like it was identity. Then again (0, 0, z) on the result like
879 	 * it was identity. Thus it works in similar vein as quaternion
880 	 * multiplication.
881 	 * 
882 	 * @param order
883 	 * @return
884 	 */
885 	public Rotation getQuatLikeRotationSeq(Rotation.Order order) {
886 		Location projected = new Location(1, 0, 0);
887 
888 		double yaw = 0d, pitch = 0d;
889 		switch (order) {
890 		case ROLL_YAW_PITCH:
891 			yaw = Math.atan2(getY(), getX());
892 			projected = projected.mul(Rotation.constructXYRot(yaw));
893 
894 			pitch = Math.atan2(getZ(), new Location(getX(), getY(), 0)
895 					.dot(projected));
896 
897 			return new Rotation(pitch / Math.PI * 32768 - 1, yaw / Math.PI
898 					* 32768 - 1, 0);
899 		}
900 		return new Rotation();
901 	}
902 
903 	/**
904 	 * Normalizes this Location
905 	 * 
906 	 * @return normalized
907 	 */
908 	public Location getNormalized() {
909 		return scale(1 / getLength());
910 	}
911 
912 	/**
913 	 * Calculates length of Location
914 	 * 
915 	 * @return length
916 	 */
917 	public double getLength() {
918 		return Math.sqrt(x * x + y * y + z * z);
919 	}
920 
921 	/**
922 	 * Projects this Location (vector) using matrix from parameter
923 	 * 
924 	 * @param matrix
925 	 *            projection matrix
926 	 * @return resulting Location
927 	 */
928 	public Location mul(Matrix3d matrix) {
929 		Location res = new Location();
930 		res.x = matrix.getM00() * x + matrix.getM10() * y + matrix.getM20() * z;
931 		res.y = matrix.getM01() * x + matrix.getM11() * y + matrix.getM21() * z;
932 		res.z = matrix.getM02() * x + matrix.getM12() * y + matrix.getM22() * z;
933 
934 		return res;
935 	}
936 
937 	/**
938 	 * Calculates inverse Location
939 	 * 
940 	 * @return new inverted Location
941 	 */
942 	public Location invert() {
943 		return new Location(-x, -y, -z);
944 	}
945 
946 	/**
947 	 * Set content of this location from passed tocation.
948 	 * 
949 	 * @return this with newly set value
950 	 */
951 	public Location setTo(Location l) {
952 		this.x = l.x;
953 		this.y = l.y;
954 		this.z = l.z;
955 
956 		return this;
957 	}
958 
959 	/**
960 	 * Set content of this location from passed data.
961 	 * 
962 	 * @return this with newly set value
963 	 */
964 	public Location setTo(double x, double y, double z) {
965 		this.x = x;
966 		this.y = y;
967 		this.z = z;
968 
969 		return this;
970 	}
971 
972 	/* ********************************************************************** */
973 
974 	public boolean equals(Object o) {
975 		if (o == null) return false;
976 		if (!(o instanceof Location)) return false;
977 		Location l = (Location)o;
978 		return getDistance(l) < DISTANCE_ZERO; 
979 	}
980 	
981 	@Override
982 	public String toString() {
983 		return String.format(Locale.ENGLISH, "[%.2f; %.2f; %.2f]", x, y, z);
984 	}
985 
986 }