www.pudn.com > Sterren_ASe_Explorer.rar > ase_losscan.cpp
/* Copyright (C) William van der Sterren, 2002. * All rights reserved worldwide. * * This software is provided "as is" without express or implied * warranties. You may freely copy and compile this source into * applications you distribute provided that the copyright text * below is included in the resulting source code, for example: * "Portions Copyright (C) William van der Sterren, 2002" */ /*************************************************************************** * * purpose: class to compute and record sector-based line-of-sight info */ #include "stdafx.h" #include "ase_losscan.h" #include#include // atan #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif int ASE_LineOfSightScan::m_kOutOfReachDistance = -1; int ASE_LineOfSightScan::m_kFarDistance = -1; int ASE_LineOfSightScan::m_kMediumDistance = -1; const unsigned int ASE_LineOfSightScan::m_kNumberOfSectors = 8; const float ASE_LineOfSightScan::m_kSectorWidthInDegrees = 360.0f / m_kNumberOfSectors; ASE_LineOfSightScan::ASE_LineOfSightScan() : m_LOSDirections(0) { } unsigned int ASE_LineOfSightScan::GetSectorForLine(int deltaX, int deltaY) { assert( m_kSectorWidthInDegrees == 45.0f ); // hardwired for 45 degrees sectors // sectors are numbered as follows: 0 degrees -> 0, 45 -> 1, 90 -> 2 ... static const float kSmallPositiveNumber = 1e-6F; static const double kPI = 4 * atan(1.0); static const float kSector0Sector1Border = static_cast (tan(22.5 / 180 * kPI)); static const float kSector1Sector2Border = static_cast (tan(67.5 / 180 * kPI)); float x; float y; x = static_cast (deltaX); y = static_cast (deltaY); unsigned int result; bool bFlippedX; bool bFlippedY; // assignment and comparison in one!! if ( bFlippedY = (y < 0) ) y *= -1; if ( bFlippedX = (x < 0) ) x *= -1; if ( x < kSmallPositiveNumber ) { result = 2; } else { float fraction; fraction = y / x; if ( fraction < kSector0Sector1Border ) result = 0; else if ( fraction < kSector1Sector2Border ) result = 1; else result = 2; } if ( bFlippedX ) { result = 4 - result; } if ( bFlippedY ) { // flipped sign, so flip result result = (m_kNumberOfSectors - result) % m_kNumberOfSectors; } return result; } void ASE_LineOfSightScan::SetThreatReachDistance(int theDistance) { /*! partition the range as follows: out of reach = from 1+ to beyond far = from 2/3 to 1 medium = from 1/3 to 2/3 near = from 0 to 1/3 */ m_kOutOfReachDistance = theDistance + 1; m_kFarDistance = m_kOutOfReachDistance * 2 / 3; m_kMediumDistance = m_kOutOfReachDistance * 1 / 3; } bool ASE_LineOfSightScan::IsANearDistanceSqrd(int theDistanceSquared) { assert( m_kMediumDistance > 0 ); return ( theDistanceSquared < ( m_kMediumDistance * m_kMediumDistance) ); } bool ASE_LineOfSightScan::IsAMediumDistanceSqrd(int theDistanceSquared) { assert( m_kMediumDistance > 0 ); assert( m_kFarDistance > 0 ); return ( ( theDistanceSquared < ( m_kFarDistance * m_kFarDistance) ) && ( theDistanceSquared >= ( m_kMediumDistance * m_kMediumDistance) ) ); } bool ASE_LineOfSightScan::IsAFarDistanceSqrd(int theDistanceSquared) { assert( m_kFarDistance > 0 ); assert( m_kOutOfReachDistance > 0 ); return ( ( theDistanceSquared < ( m_kOutOfReachDistance * m_kOutOfReachDistance) ) && ( theDistanceSquared >= ( m_kFarDistance * m_kFarDistance) ) ); } bool ASE_LineOfSightScan::IsOutOfReachSqrd(int theDistanceSquared) { assert( m_kOutOfReachDistance > 0 ); return ( theDistanceSquared >= ( m_kOutOfReachDistance * m_kOutOfReachDistance) ); } ASE_LineOfSightScan::word ASE_LineOfSightScan::GetValueForSector(ASE_LineOfSightScan::word aValue, unsigned int aSector) { assert( aSector < m_kNumberOfSectors ); const word kMask = 3; word result; result = ( aValue >> (2 * aSector) ) & kMask; return result; } ASE_LineOfSightScan::word ASE_LineOfSightScan::SetValueForSector(ASE_LineOfSightScan::word aValue, ASE_LineOfSightScan::word aSectorValue, unsigned int aSector) { assert( aSector < m_kNumberOfSectors ); assert( aSectorValue < 4 ); const word kMask = (3 << ( 2 * aSector)); word shiftedSValue = (aSectorValue << ( 2 * aSector) ); assert( shiftedSValue == ( kMask & shiftedSValue ) ); word result; result = (aValue - ( aValue & kMask) + shiftedSValue ); return result; } ASE_LineOfSightScan::ScanValue ASE_LineOfSightScan::GetObservationFromPosition(int thisPositionX, int thisPositionY, int theObserverX, int theObserverY ) const { int deltaX; int deltaY; deltaX = theObserverX - thisPositionX; deltaY = theObserverY - thisPositionY; int distanceSquared; distanceSquared = deltaX * deltaX + deltaY * deltaY; ScanValue result; if ( IsOutOfReachSqrd(distanceSquared) ) result = eNotObserved; else { unsigned int sector; sector = GetSectorForLine(deltaX, deltaY); ScanValue los; los = static_cast (GetValueForSector(m_LOSDirections, sector)); if ( los == eNotObserved ) result = eNotObserved; else if ( ( IsAFarDistanceSqrd(distanceSquared) ) && ( los == eObservedFromFarDistance ) ) result = eObservedFromFarDistance; else if ( ( IsAMediumDistanceSqrd(distanceSquared) ) && ( los <= eObservedFromMediumDistance ) ) result = eObservedFromMediumDistance; else if ( ( IsANearDistanceSqrd(distanceSquared) ) // && ( los <= eObservedFromNearDistance ) ) result = eObservedFromNearDistance; else result = eNotObserved; } return result; } void ASE_LineOfSightScan::Clear() { m_LOSDirections = 0; } void ASE_LineOfSightScan::SetNoCoverAtAll() { m_LOSDirections = 0; for ( unsigned int sector = 0; sector < m_kNumberOfSectors; ++sector ) { UpdateSector(sector, eObservedFromFarDistance); } } void ASE_LineOfSightScan::UpdateSector(unsigned int aSector, ScanValue aValue) { m_LOSDirections = SetValueForSector(m_LOSDirections, aValue, aSector); } void ASE_LineOfSightScan::ComputeLOSApproximation (int thisPositionX, int thisPositionY, const CoordPairList& thePositionsObservingThisPosition ) { // init all flags to false (not observed) m_LOSDirections = 0; // iterate over all observing positions CoordPairList::const_iterator position; for ( position = thePositionsObservingThisPosition.begin(); position != thePositionsObservingThisPosition.end(); ++position ) { int deltaX; int deltaY; deltaX = position->x - thisPositionX; deltaY = position->y - thisPositionY; int distanceSquared; distanceSquared = deltaX * deltaX + deltaY * deltaY; if ( IsOutOfReachSqrd(distanceSquared) ) continue; unsigned int sector; sector = GetSectorForLine(deltaX, deltaY); word value; ScanValue newvalue; value = GetValueForSector(m_LOSDirections, sector); if ( IsAFarDistanceSqrd(distanceSquared) ) newvalue = eObservedFromFarDistance; else if ( IsAMediumDistanceSqrd(distanceSquared) ) newvalue = eObservedFromMediumDistance; else newvalue = eObservedFromNearDistance; if ( ( value == 0 ) || ( ( newvalue > 0 ) && ( newvalue < value ) ) ) UpdateSector(sector, newvalue); } } unsigned int ASE_LineOfSightScan::GetNumberOfSectors() { return m_kNumberOfSectors; }