ase_losapproxboard.cpp

来自「A*算法的演示程序」· C++ 代码 · 共 637 行 · 第 1/2 页

CPP
637
字号
    const int kEntries = GetNumberOfColumns() * GetNumberOfRows();

    for ( unsigned int idx = 0; idx < kEntries; ++idx )
      {
        unsigned int row;
        unsigned int col;
        GetRowAndColumnForIndex(idx, row, col);

        if ( m_kTerrainBoard->IsLocationImpassable(row, col) )
          {
            ASE_CoordPair pos(row, col);
            m_ObstaclePositions.push_back(pos);
          }
      }
  }


bool ASE_LOSApproximationBoard::IsAnyObstacleWithinRange(int x, int y, int theRange) const
  {
    const int rangeSqr = theRange * theRange;

    CoordPairList::const_iterator pos;
    for ( pos =  m_ObstaclePositions.begin();
          pos != m_ObstaclePositions.end();
          ++pos
        )
      {
        int dx;
        int dy;
        int dsqr;
        dx   = pos->x - x;
        dy   = pos->y - y;
        dsqr = dx * dx + dy * dy;
 
        if ( dsqr <= rangeSqr )
          return true;
      }
    return false;
  }


bool ASE_LOSApproximationBoard::IsAnyObstacleWithinRangeAndSector(int x, int y, int theRange, unsigned int aSector) const
  {
    const int rangeSqr = theRange * theRange;

    CoordPairList::const_iterator pos;
    for ( pos =  m_ObstaclePositions.begin();
          pos != m_ObstaclePositions.end();
          ++pos
        )
      {
        int dx;
        int dy;
        int dsqr;
        dx   = pos->x - x;
        dy   = pos->y - y;
        dsqr = dx * dx + dy * dy;
 
        if ( dsqr > rangeSqr )
          continue;

        unsigned int sector;
        sector = ASE_LineOfSightScan::GetSectorForLine(dx, dy);
 
        if ( sector == aSector )
          return true;
      }
    return false;
  }


unsigned int ASE_LOSApproximationBoard::GetDistanceToNearestObstacleWithinRangeAndSector(int x, int y, int theRange, unsigned int aSector) const
  {
    const int rangeSqr = theRange * theRange;

    int minSqr = ( (theRange + 1) * (theRange + 1) );

    CoordPairList::const_iterator pos;
    for ( pos =  m_ObstaclePositions.begin();
          pos != m_ObstaclePositions.end();
          ++pos
        )
      {
        int dx;
        int dy;
        int dsqr;
        dx   = pos->x - x;
        dy   = pos->y - y;
        dsqr = dx * dx + dy * dy;
 
        if ( dsqr > rangeSqr )
          continue;

        unsigned int sector;
        sector = ASE_LineOfSightScan::GetSectorForLine(dx, dy);
 
        if ( sector == aSector )
          {
            minSqr = min(minSqr, dsqr);
          }
      }
    return static_cast<unsigned int>(minSqr);
  }


void ASE_LOSApproximationBoard::SetLocationAsLackingAnyCover(int x, int y)
  {
    ASE_LineOfSightScan los;
    los.SetNoCoverAtAll();

    unsigned int idx;
    idx = GetIndexForRowColumn(x, y);

    m_LineOfSightScanInfos[idx] = los;
  }


void ASE_LOSApproximationBoard::ApproximateLOFForLocationBySector(int x, int y)
  {
    unsigned int idx;
    idx = GetIndexForRowColumn(x, y);

    m_LineOfSightScanInfos[idx].Clear();

    for ( unsigned int sector = 0; sector < ASE_LineOfSightScan::GetNumberOfSectors(); ++sector )
      {
        unsigned int obstSqr;
        obstSqr = GetDistanceToNearestObstacleWithinRangeAndSector(x, y, m_kThreatBoard->GetMaxThreatReach(), sector);

        if (   ( ASE_LineOfSightScan::IsOutOfReachSqrd(obstSqr) )
            || ( ASE_LineOfSightScan::IsAFarDistanceSqrd(obstSqr) )
           )
          {
            m_LineOfSightScanInfos[idx].UpdateSector(sector, ASE_LineOfSightScan::eObservedFromFarDistance);
          }
        else
          {
            ComputeSectorLOSForLocation(x, y, sector, m_kThreatBoard->GetMaxThreatReach());
          }
      }
  } 


void ASE_LOSApproximationBoard::ComputeSectorLOSForLocation(int x, int y, unsigned int aSector, unsigned int aRange)
  {
    // try each applicable ray from the template for this sector, until getting a eObservedFromFarDistance
    const ASE_PieScan* pie = m_kThreatBoard->GetLineOfSightTemplate();

    unsigned int nr_of_rays;
    nr_of_rays = pie->GetNumberOfRays();

    ASE_CoordPair here(x, y);
    CoordPairList raytrace;

    const int minmaxdistsqr = static_cast<int>(aRange * aRange);
    int maxdistsqr          = 0;

    for ( unsigned int ray = 0; ray < nr_of_rays; ++ray )
      {
        if ( pie->IsRayInSector(ray, aSector) )
          {
            raytrace.clear();
            pie->GetRayForLocation(ray, here, raytrace);

            CoordPairList::const_iterator pos;
            for ( pos =  raytrace.begin(); 
                  pos != raytrace.end(); 
                  ++pos
                )
              {
                if ( !IsValidBoardLocation(pos->x, pos->y) )
                  break;

                if ( m_kTerrainBoard->IsLocationImpassable(pos->x, pos->y) )
                  break;
              }

            // determine distance sqr
            if (   ( pos != raytrace.end() )
                && ( pos != raytrace.begin() )
               ) 
              {
                int dx;
                int dy;
                int dsqr;
                dx   = pos->x - x;
                dy   = pos->y - y;
                dsqr = (dx * dx) + (dy * dy);

                maxdistsqr = max(maxdistsqr, dsqr); 
              }
            else
            if ( pos == raytrace.end() )
              {
                maxdistsqr = minmaxdistsqr; 
              }

            // test for bail out
            if ( maxdistsqr >= minmaxdistsqr )
              break;
          }
      }

    // check max distance, and set los accordingly
    ASE_LineOfSightScan::ScanValue value;
    if (   ( ASE_LineOfSightScan::IsOutOfReachSqrd(maxdistsqr) )
        || ( ASE_LineOfSightScan::IsAFarDistanceSqrd(maxdistsqr) )
       ) 
      value = ASE_LineOfSightScan::eObservedFromFarDistance;
    else
    if ( maxdistsqr == 0 )
      value = ASE_LineOfSightScan::eNotObserved;
    else
    if ( ASE_LineOfSightScan::IsAMediumDistanceSqrd(maxdistsqr) )
      value = ASE_LineOfSightScan::eObservedFromMediumDistance;
    else
      value = ASE_LineOfSightScan::eObservedFromNearDistance;

    unsigned int idx;
    idx = GetIndexForRowColumn(x, y);
    m_LineOfSightScanInfos[idx].UpdateSector(aSector, value);
  }


void ASE_LOSApproximationBoard::UpdateBoard()
  {
    /*! now update the board values, signaling danger positions
        given current threats

        1. set all cells to safe (0)
        2. iterate over each threat
           - then iterate over every position within reach of the threat
           - if position is visible by threat, mark as danger
    */
    const int kEntries = GetNumberOfColumns() * GetNumberOfRows();

    CoordPairList kThreatPositions;
    m_kThreatBoard->GetThreatPositions(kThreatPositions);

    for ( unsigned int idx = 0; idx < kEntries; ++idx )
      {
        unsigned int row;
        unsigned int col;
        GetRowAndColumnForIndex(idx, row, col);

        CellValue value;
        value = 0;
        
        // iterate over all known threats, and update value accordingly
        CoordPairList::const_iterator threat;
        for ( threat =  kThreatPositions.begin(); 
              threat != kThreatPositions.end(); 
              ++threat
            )
          {
            ASE_LineOfSightScan::ScanValue los1;
            ASE_LineOfSightScan::ScanValue los2;
            los1 = m_LineOfSightScanInfos[idx].GetObservationFromPosition(row, col, threat->x, threat->y);

            unsigned int jdx;
            jdx  = GetIndexForRowColumn(threat->x, threat->y);
            los2 = m_LineOfSightScanInfos[jdx].GetObservationFromPosition(threat->x, threat->y, row, col);

            if (   ( los1 != ASE_LineOfSightScan::eNotObserved )
                && ( los2 != ASE_LineOfSightScan::eNotObserved )
               )
              {  
                value = max(value, static_cast<CellValue>(los1));
              }
          }
        // skip over 'green' value
        if ( value > 0 )
          value++;

        SetCellValue(idx, value);
      }
  }


/*
void ASE_LOSApproximationBoard::ComputeLinesOfFireApproximation()
  {
     ComputeLinesOfFireApproximation2();

     if ( !DidAnythingChange() )
       return;

     ASE_LineOfSightScan::SetThreatReachDistance(m_kThreatBoard->GetMaxThreatReach());

     int minx;
     int miny;
     int maxx;
     int maxy;
     GetChangeRange(minx, miny, maxx, maxy);

     // adjust for threat range
     minx = max(0, minx - m_kThreatBoard->GetMaxThreatReach());
     miny = max(0, miny - m_kThreatBoard->GetMaxThreatReach());
     maxx = min(-1 + GetNumberOfColumns(), maxx + m_kThreatBoard->GetMaxThreatReach());
     maxy = min(-1 + GetNumberOfRows(),    maxy + m_kThreatBoard->GetMaxThreatReach());

     InitObserversLOS(minx, miny, maxx, maxy);

     // fall back on original area
     GetChangeRange(minx, miny, maxx, maxy);
     minx = max(0, minx);
     miny = max(0, miny);
     maxx = min(-1 + GetNumberOfColumns(), maxx);
     maxy = min(-1 + GetNumberOfRows(),    maxy);

     ProcessLocations(minx, miny, maxx, maxy);
     UpdateBoard(minx, miny, maxx, maxy);

     ResetChangeRange();
  }
*/

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?