PageRenderTime 49ms CodeModel.GetById 25ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

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