001/** 002 * Copyright (c) 2008-2014 Ardor Labs, Inc. 003 * 004 * This file is part of Ardor3D. 005 * 006 * Ardor3D is free software: you can redistribute it and/or modify it 007 * under the terms of its license which may be found in the accompanying 008 * LICENSE file or at <http://www.ardor3d.com/LICENSE>. 009 */ 010 011package com.ardor3d.intersection; 012 013import java.util.ArrayList; 014import java.util.Collections; 015import java.util.Comparator; 016import java.util.List; 017 018import com.ardor3d.math.Ray3; 019 020/** 021 * PickResults stores information created during ray intersection tests. The results will contain a list of every 022 * {@link Pickable} element encountered in a pick test. Distance can be used to order the results. If checkDistance is 023 * set to true, objects will be ordered with the first element in the list being the closest picked object. 024 */ 025public abstract class PickResults { 026 027 private final List<PickData> _nodeList; 028 private boolean _checkDistance; 029 private DistanceComparator _distanceCompare; 030 031 /** 032 * Constructor instantiates a new <code>PickResults</code> object. 033 */ 034 public PickResults() { 035 _nodeList = new ArrayList<>(); 036 } 037 038 /** 039 * remember modification of the list to allow sorting after all picks have been added - not each time. 040 */ 041 private boolean modified = false; 042 043 /** 044 * Places a new geometry (enclosed in PickData) into the results list. 045 * 046 * @param data 047 * the PickData to be placed in the results list. 048 */ 049 public void addPickData(final PickData data) { 050 _nodeList.add(data); 051 modified = true; 052 } 053 054 /** 055 * <code>getNumber</code> retrieves the number of geometries that have been placed in the results. 056 * 057 * @return the number of Mesh objects in the list. 058 */ 059 public int getNumber() { 060 return _nodeList.size(); 061 } 062 063 /** 064 * Retrieves a geometry (enclosed in PickData) from a specific index. 065 * 066 * @param i 067 * the index requested. 068 * @return the data at the specified index. 069 */ 070 public PickData getPickData(final int i) { 071 if (modified) { 072 if (_checkDistance) { 073 Collections.sort(_nodeList, _distanceCompare); 074 } 075 modified = false; 076 } 077 return _nodeList.get(i); 078 } 079 080 /** 081 * <code>clear</code> clears the list of all Mesh objects. 082 */ 083 public void clear() { 084 _nodeList.clear(); 085 } 086 087 /** 088 * <code>addPick</code> generates an entry to be added to the list of picked objects. If checkDistance is true, the 089 * implementing class should order the object. 090 * 091 * @param ray 092 * the ray that was cast for the pick calculation. 093 * @param p 094 * the pickable object to add to the pick data. 095 */ 096 public abstract void addPick(Ray3 ray, Pickable p); 097 098 /** 099 * Optional method that can be implemented by sub classes to define methods for handling picked objects. After 100 * calculating all pick results this method is called. 101 * 102 */ 103 public void processPick() {} 104 105 /** 106 * Reports if these pick results will order the data by distance from the origin of the Ray. 107 * 108 * @return true if objects will be ordered by distance, false otherwise. 109 */ 110 public boolean willCheckDistance() { 111 return _checkDistance; 112 } 113 114 /** 115 * Sets if these pick results will order the data by distance from the origin of the Ray. 116 * 117 * @param checkDistance 118 * true if objects will be ordered by distance, false otherwise. 119 */ 120 public void setCheckDistance(final boolean checkDistance) { 121 _checkDistance = checkDistance; 122 if (checkDistance) { 123 _distanceCompare = new DistanceComparator(); 124 } 125 } 126 127 /** 128 * Implementation of comparator that uses the distance set in the pick data to order the objects. 129 */ 130 private static class DistanceComparator implements Comparator<PickData> { 131 132 @Override 133 public int compare(final PickData o1, final PickData o2) { 134 if (o1.getIntersectionRecord().getClosestDistance() == o2.getIntersectionRecord().getClosestDistance()) { 135 return 0; 136 } 137 if (o1.getIntersectionRecord().getClosestDistance() < o2.getIntersectionRecord().getClosestDistance()) { 138 return -1; 139 } 140 141 return 1; 142 } 143 } 144 145 public PickData findFirstIntersectingPickData() { 146 int i = 0; 147 while (getNumber() > 0 && getPickData(i).getIntersectionRecord().getNumberOfIntersections() == 0 148 && ++i < getNumber()) { 149 } 150 return getNumber() > i ? getPickData(i) : null; 151 } 152}