/src/org/mt4j/components/PickResult.java

http://mt4j.googlecode.com/ · Java · 295 lines · 121 code · 41 blank · 133 comment · 19 complexity · 5f7de4788254a86ce7c0ee666babb9dc MD5 · raw file

  1. /***********************************************************************
  2. * mt4j Copyright (c) 2008 - 2009, C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. ***********************************************************************/
  18. package org.mt4j.components;
  19. import java.util.ArrayList;
  20. import java.util.Collections;
  21. import java.util.List;
  22. import org.mt4j.util.math.Vector3D;
  23. /**
  24. * Acts as a visitor to the scene and collects the pick information if
  25. * any objects were hit (picked).
  26. * Later, whe can retrieve the nearest picked object and its intersection point.
  27. *
  28. * @author Christopher Ruff
  29. */
  30. public class PickResult {
  31. /** The pick list. */
  32. // private ArrayList<MTComponent> pickList;
  33. /** The comp to inter section point. */
  34. // private WeakHashMap<MTComponent, Vector3D[]> compToInterSectionPoint;
  35. private List<PickEntry> pickEntries;
  36. private boolean isAlreadySorted;
  37. /**
  38. * Sometimes the wrong obj gets picked if they are on the same plane but with different inverted rays..
  39. * probably math rounding off errors with floats etc. (at inverting the ray?)
  40. * <br>This makes sure, objs which are checked later for a hit,
  41. * (and are probably drawn ontop of the previous ones because drawn later),
  42. * are picked more likely.
  43. * <br>Still this is kind of a hack
  44. */
  45. public static final float HIT_TOLERANCE = 0.1f; //0.03f; //FIXME reset to old value!?
  46. /**
  47. * Instantiates a new pick result.
  48. */
  49. public PickResult() {
  50. super();
  51. // pickList = new ArrayList<MTComponent>();
  52. // compToInterSectionPoint = new WeakHashMap<MTComponent, Vector3D[]>();
  53. pickEntries = new ArrayList<PickEntry>();
  54. isAlreadySorted = false;
  55. }
  56. /**
  57. * This should only be called by the scene while this objects visits all scene nodes.
  58. *
  59. * @param hitObject the hit object
  60. * @param intersectionPoint the intersection point
  61. * @param distance the distance
  62. */
  63. public void addPickedObject(MTComponent hitObject, Vector3D intersectionPoint, float distance){
  64. // pickList.add(hitObject);
  65. // compToInterSectionPoint.put(hitObject, new Vector3D[]{intersectionPoint, new Vector3D(distance,distance,distance)}); //hack
  66. pickEntries.add(new PickEntry(hitObject, intersectionPoint, distance));
  67. int lastIndex = pickEntries.size()-1;
  68. pickEntries.get(lastIndex).originalOrderIndex = lastIndex;
  69. isAlreadySorted = false;
  70. }
  71. /**
  72. * Returns the picked component.
  73. * This is the last in the list of picked components, not neccessarily the one with
  74. * the shortest distance from the pickray (<code>setComposite</code> can interfere with that). But usually it should be
  75. * the nearest one to the origin of the pick. :)
  76. *
  77. * @return the nearest pick result
  78. *
  79. * the picked component or null if nothing could be picked
  80. */
  81. public MTComponent getNearestPickResult(){
  82. if (this.isEmpty())
  83. return null;
  84. else{
  85. return this.getPickList().get(0).hitObj;
  86. // return this.pickEntries.get(pickEntries.size()-1).hitObj;
  87. }
  88. /*
  89. if (this.isEmpty())
  90. return null;
  91. else
  92. return pickList.get(pickList.size()-1);
  93. */
  94. }
  95. public PickEntry getNearestPickEntry(){
  96. if (this.isEmpty())
  97. return null;
  98. else{
  99. return this.getPickList().get(0);
  100. // return this.pickEntries.get(pickEntries.size()-1).hitObj;
  101. }
  102. }
  103. /**
  104. * Gets the pick list.
  105. *
  106. * @return the pick list
  107. */
  108. public List<PickEntry> getPickList() {
  109. // return pickList;
  110. this.sort();
  111. return pickEntries;
  112. }
  113. // public void addPickedObjects(ArrayList<MTBaseComponent> pickList) {
  114. // pickList.addAll(pickList);
  115. // }
  116. /**
  117. * Returns the distance of the origin of the pick to the nearest picked obj.
  118. *
  119. * @return the distance nearest pick obj
  120. */
  121. public float getDistanceNearestPickObj(){
  122. // if (this.isEmpty()){
  123. // return Float.MAX_VALUE;
  124. // }else{
  125. // return getDistanceOfPickedObj(this.getNearestPickResult());
  126. // }
  127. return getNearestPickEntry().cameraDistance;
  128. }
  129. /**
  130. * Returns the distance of the origin of the pick to the specified picked obj.
  131. *
  132. * @param pickedObj the picked obj
  133. *
  134. * @return the distance of picked obj
  135. */
  136. public float getDistanceOfPickedObj(MTComponent pickedObj){
  137. // return compToInterSectionPoint.get(pickedObj)[1].x;
  138. for (int i = 0; i < getPickList().size(); i++) {
  139. PickEntry p = pickEntries.get(i);
  140. if (p.hitObj.equals(pickedObj))
  141. return p.cameraDistance;
  142. }
  143. return Float.MAX_VALUE;
  144. }
  145. /**
  146. * Returns the interseciton point of the specified picked obj.
  147. * Returns null if the object isnt in the pick list!
  148. *
  149. * @param pickedObj the picked obj
  150. *
  151. * @return the inter section point of picked obj
  152. */
  153. public Vector3D getInterSectionPointOfPickedObj(MTComponent pickedObj){
  154. // return compToInterSectionPoint.get(pickedObj)[0];
  155. for (int i = 0; i < getPickList().size(); i++) {
  156. PickEntry p = pickEntries.get(i);
  157. if (p.hitObj.equals(pickedObj))
  158. return p.intersectionPoint;
  159. }
  160. return null;
  161. }
  162. /**
  163. * Gets the inter section point nearest picked obj.
  164. *
  165. * @return the inter section point nearest picked obj
  166. */
  167. public Vector3D getInterSectionPointNearestPickedObj(){
  168. if (this.isEmpty()){
  169. return null;
  170. }else{
  171. return getInterSectionPointOfPickedObj(this.getNearestPickResult());
  172. }
  173. }
  174. /**
  175. * Checks if is empty.
  176. *
  177. * @return true, if is empty
  178. */
  179. public boolean isEmpty(){
  180. // return pickList.isEmpty();
  181. return pickEntries.isEmpty();
  182. }
  183. public void sort() {
  184. if (!isAlreadySorted){
  185. Collections.sort(pickEntries);
  186. isAlreadySorted = true;
  187. // printList();
  188. }
  189. }
  190. public void printList() {
  191. sort();
  192. System.out.println("Pick Entries:");
  193. for (PickEntry p : pickEntries) {
  194. System.out.println("Entry: " + p.hitObj + " Distance: " + p.cameraDistance + " Intersection: " + p.intersectionPoint);
  195. }
  196. }
  197. public class PickEntry implements Comparable<PickEntry>{
  198. public int originalOrderIndex;
  199. public Vector3D intersectionPoint;
  200. public float cameraDistance;
  201. public MTComponent hitObj;
  202. public PickEntry(MTComponent hitObject, Vector3D intersectionPoint2, float distance) {
  203. this.hitObj = hitObject;
  204. this.intersectionPoint = intersectionPoint2;
  205. this.cameraDistance = distance;
  206. }
  207. //We give the later picked objects with the same distance priority
  208. //(by substracting the hit tolerance from their distance)
  209. //We do this because they are probably drawn ontop because they are located later in the scene graph
  210. //Also, we priorize objects that are drawn with depth buffer disabled because they are also in front of others,
  211. //even if camera distance is farther
  212. public int compareTo(PickEntry o2) {
  213. if (o2.equals(this)){
  214. return 0;
  215. }
  216. if (this.originalOrderIndex >= o2.originalOrderIndex){
  217. if (this.cameraDistance - HIT_TOLERANCE <= o2.cameraDistance || isDrawnWithoutDepthBuffer(this.hitObj)){
  218. return -1;
  219. }else{
  220. return 1;
  221. }
  222. }else{
  223. if (o2.cameraDistance - HIT_TOLERANCE <= this.cameraDistance || isDrawnWithoutDepthBuffer(o2.hitObj)){
  224. return 1;
  225. }else{
  226. return -1;
  227. }
  228. }
  229. }
  230. // public boolean addedAfter(PickEntry other){
  231. // return this.originalOrderIndex >= other.originalOrderIndex;
  232. // }
  233. /**
  234. * Checks if is drawn without depth buffer.
  235. * Since this is inherited to children we have to check
  236. * the parents.
  237. *
  238. * @param comp the comp
  239. *
  240. * @return true, if is drawn without depth buffer
  241. */
  242. public boolean isDrawnWithoutDepthBuffer(MTComponent comp){
  243. if (comp.isDepthBufferDisabled())
  244. return true;
  245. MTComponent p = comp.getParent();
  246. while (p != null){
  247. if (p.isDepthBufferDisabled())
  248. return true;
  249. p = p.getParent();
  250. }
  251. return false;
  252. }
  253. }
  254. }