00001 /************************************************************************* 00002 * * 00003 * Open Physics Abstraction Layer * 00004 * Copyright (C) 2004-2005 * 00005 * Alan Fischer alan.fischer@gmail.com * 00006 * Andres Reinot andres@reinot.com * 00007 * Tyler Streeter tylerstreeter@gmail.com * 00008 * All rights reserved. * 00009 * Web: opal.sourceforge.net * 00010 * * 00011 * This library is free software; you can redistribute it and/or * 00012 * modify it under the terms of EITHER: * 00013 * (1) The GNU Lesser General Public License as published by the Free * 00014 * Software Foundation; either version 2.1 of the License, or (at * 00015 * your option) any later version. The text of the GNU Lesser * 00016 * General Public License is included with this library in the * 00017 * file license-LGPL.txt. * 00018 * (2) The BSD-style license that is included with this library in * 00019 * the file license-BSD.txt. * 00020 * * 00021 * This library is distributed in the hope that it will be useful, * 00022 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * 00024 * license-LGPL.txt and license-BSD.txt for more details. * 00025 * * 00026 *************************************************************************/ 00027 00028 // project headers 00029 #include "RaycastSensor.h" 00030 #include "Simulator.h" 00031 00032 // system headers 00033 #include <algorithm> 00034 00035 using namespace std; 00036 00037 namespace opal 00038 { 00039 RaycastSensor::RaycastSensor( Simulator* s ) 00040 { 00041 // "mData" is initialized in its own constructor. 00042 mSim = s; 00043 } 00044 00045 RaycastSensor::~RaycastSensor() 00046 {} 00047 00048 void RaycastSensor::init( const RaycastSensorData& data ) 00049 { 00050 Sensor::init(); 00051 mData = data; 00052 } 00053 00054 const RaycastSensorData& RaycastSensor::getData() const 00055 { 00056 return mData; 00057 } 00058 00059 const RaycastResult & RaycastSensor::fireRay() 00060 { 00061 return fireRay( mData.ray.getLength() ); 00062 } 00063 00064 const vector<RaycastResult> & RaycastSensor::firePiercingRay() 00065 { 00066 return firePiercingRay( mData.ray.getLength() ); 00067 } 00068 00069 const RaycastResult & RaycastSensor::fireRay( real length ) 00070 { 00071 static RaycastResult junkResult; 00072 00073 if ( mData.enabled ) 00074 { 00075 Rayr ray = mData.ray; 00076 00077 // If the Sensor is attached to a Solid, we need to transform 00078 // the ray relative to that Solid's transform. 00079 if ( mData.solid ) 00080 { 00081 ray = mData.solid->getTransform() * mData.transform * ray; 00082 } 00083 else 00084 { 00085 // If the Sensor is not attached to a Solid, just use the 00086 // Sensor's transform as a global transform on the ray. 00087 ray = mData.transform * ray; 00088 } 00089 00090 // If this is attached to a Solid, the Simulator raycast function 00091 // will automatically ignore intersections between the ray and 00092 // that Solid. 00093 00094 vector<RaycastResult> & results = mSim->internal_fireRay( 00095 ray, length, mData.solid, mData.contactGroup ); 00096 00097 if ( results.size() == 0 ) 00098 return junkResult; 00099 00100 size_t closest = 0; 00101 for ( size_t i = 1; i < results.size(); ++i ) 00102 { 00103 if ( results[ i ].distance < results[ closest ].distance ) 00104 closest = i; 00105 } 00106 00107 return results[ closest ]; 00108 } 00109 else 00110 { 00111 return junkResult; 00112 } 00113 } 00114 00115 const vector<RaycastResult> & RaycastSensor::firePiercingRay( real length ) 00116 { 00117 static vector<RaycastResult> empty; 00118 00119 if ( mData.enabled ) 00120 { 00121 // the original ray shouldn't change 00122 Rayr ray = mData.ray; 00123 00124 // If the Sensor is attached to a Solid, we need to transform 00125 // the ray relative to that Solid's transform. 00126 if ( mData.solid ) 00127 { 00128 ray = mData.solid->getTransform() * mData.transform * ray; 00129 } 00130 else 00131 { 00132 // If the Sensor is not attached to a Solid, just use the 00133 // Sensor's transform as a global transform on the ray. 00134 ray = mData.transform * ray; 00135 } 00136 00137 // If this is attached to a Solid, the Simulator raycast function 00138 // will automatically ignore intersections between the ray and 00139 // that Solid. 00140 00141 vector<RaycastResult> & results = mSim->internal_fireRay( 00142 ray, length, mData.solid, mData.contactGroup ); 00143 sort( results.begin(), results.end() ); 00144 00145 return results; 00146 } 00147 else 00148 { 00149 return empty; 00150 } 00151 } 00152 00153 void RaycastSensor::setEnabled( bool e ) 00154 { 00155 //if (!mInitCalled) 00156 //{ 00157 // return; 00158 //} 00159 00160 mData.enabled = e; 00161 } 00162 00163 bool RaycastSensor::isEnabled() const 00164 { 00165 return mData.enabled; 00166 } 00167 00168 void RaycastSensor::setRay( const Rayr& r ) 00169 { 00170 mData.ray = r; 00171 } 00172 00173 const Rayr& RaycastSensor::getRay() const 00174 { 00175 return mData.ray; 00176 } 00177 00178 SensorType RaycastSensor::getType() const 00179 { 00180 return mData.getType(); 00181 } 00182 00183 void RaycastSensor::setTransform( const Matrix44r& t ) 00184 { 00185 mData.transform = t; 00186 } 00187 00188 const Matrix44r& RaycastSensor::getTransform() const 00189 { 00190 return mData.transform; 00191 } 00192 00193 void RaycastSensor::setName( const std::string& name ) 00194 { 00195 mData.name = name; 00196 } 00197 00198 const std::string& RaycastSensor::getName() const 00199 { 00200 return mData.name; 00201 } 00202 00203 void RaycastSensor::internal_update() 00204 { 00205 if ( mData.enabled && mData.solid ) 00206 { 00207 // Do nothing. 00208 } 00209 } 00210 00211 bool RaycastSensor::internal_dependsOnSolid( Solid* s ) 00212 { 00213 if ( s == mData.solid ) 00214 { 00215 return true; 00216 } 00217 else 00218 { 00219 return false; 00220 } 00221 } 00222 00223 bool operator<( const RaycastResult & l, const RaycastResult & r ) 00224 { 00225 return l.distance < r.distance; 00226 } 00227 }