public FovCone(int range, IntVector2D top, IntVector2D bottom, RiseRun riseRun) : this()
 {
     this.Range        = range;
     this.VectorTop    = top;
     this.VectorBottom = bottom;
     this.RiseRun      = riseRun;
 }
Exemple #2
0
 static IntVector2D LogAndEnqueue(Action <FovCone> enqueue, int range, IntVector2D top,
                                  IntVector2D bottom, RiseRun riseRun, int code
                                  )
 {
     if (top.GT(bottom))
     {
         var cone = new FovCone(range + 1, top, bottom, riseRun);
 #if TraceFOV
         TraceFlag.FieldOfView.Trace(false, "  EQ: ({0}) code: {1}", cone, code);
 #endif
         enqueue(cone);
         return(bottom);
     }
     else
     {
         return(top);
     }
 }
Exemple #3
0
    // This method has two main purposes: (1) it marks points inside the
    // portion that are within the radius as in the field of view, and 
    // (2) it computes which portions of the following column are in the 
    // field of view, and puts them on a work queue for later processing. 
    //
    // A more sophisticated algorithm would say that a cell is visible if there is 
    // *any* straight line segment that passes through *any* portion of the origin cell
    // and any portion of the target cell, passing through only transparent cells
    // along the way. This is the "Permissive Field Of View" algorithm, and it
    // is much harder to implement.
    //
    // Search for transitions from opaque to transparent or
    // transparent to opaque and use those to determine what
    // portions of the *next* column are visible from the origin.
    private static FovCone ComputeFoVForRange(
      int                     observerHeight,
      FovCone                 cone,
      Func<ICoordsCanon,bool> isOnBoard,
      Func<ICoordsCanon, int> targetHeight,
      Func<ICoordsCanon, int> terrainHeight,
      Action<ICoordsCanon>    setFieldOfView,
      FovQueue             queue)
    {
      Action<FovCone> enqueue = queue.Enqueue;

      var range         = cone.Range;
      var topVector     = cone.VectorTop;
      var topRiseRun    = cone.RiseRun;
      var bottomVector  = cone.VectorBottom;

      // track the overlap-cone between adjacent hexes as we move down.
      var overlapVector = cone.VectorTop;
      var hexX          = XFromVector(range, topVector, true);
      #if TraceFOV
        TraceFlag.FieldOfView.Trace(false, "DQ:   ({0}) from {1}", cone, hexX);
      #endif

      do {
        while (overlapVector.GT(bottomVector)) {
          var coordsCurrent   = HexCoords.NewCanonCoords(hexX,range);
          var hexVectorBottom = VectorHexBottom(coordsCurrent);
          if (isOnBoard(coordsCurrent)) { 
            #region Set current hex parameters
            var hexVectorTop  = VectorHexTop(coordsCurrent);
            var hexElevation  = targetHeight(coordsCurrent);
            var hexHeight     = terrainHeight(coordsCurrent);
            var hexRiseRun    = new RiseRun(hexHeight-observerHeight, range);
            #endregion

            #region Check visibility of current hex
            var riseRun = new RiseRun(hexElevation-observerHeight, GetRange(coordsCurrent));
            if ( riseRun >= cone.RiseRun  
            && bottomVector.LE(coordsCurrent.Vector) && coordsCurrent.Vector.LE(topVector)  
            ) {
              setFieldOfView(coordsCurrent);
              #if TraceFOV
                TraceFlag.FieldOfView.Trace(false,"    Set visible: {0} / {1}; {2} >= {3}", 
                    MapCoordsDodecant(coordsCurrent), coordsCurrent.ToString(), riseRun, cone.RiseRun);
              #endif
            }
            #endregion

            #region Check hex transition
            if (hexRiseRun > topRiseRun) {
              topVector  = LogAndEnqueue(enqueue, range, topVector, hexVectorTop, topRiseRun, 0);
              topRiseRun = hexRiseRun;
            } else if (hexRiseRun > cone.RiseRun) {
              topVector  = LogAndEnqueue(enqueue, range, topVector, overlapVector, topRiseRun, 1);
              topRiseRun = hexRiseRun;
            } else if (hexRiseRun < cone.RiseRun) {
              topVector  = LogAndEnqueue(enqueue, range, topVector, overlapVector, topRiseRun, 2);
              topRiseRun = cone.RiseRun;
            }
            #endregion
          }

          overlapVector = VectorMax(hexVectorBottom, bottomVector); 
          if (hexVectorBottom.GT(bottomVector))      -- hexX;
        }

        #region Dequeue next cone
        if (queue.Count == 0) {
          topVector   = LogAndEnqueue(enqueue, range, topVector, bottomVector, topRiseRun, 3);
          cone        = queue.Dequeue();
          break;
        } else {
          cone        = queue.Dequeue();
          if(cone.Range != range) {
            topVector = LogAndEnqueue(enqueue, range, topVector, bottomVector, topRiseRun, 4);
            break;
          }
          #if TraceFOV
            TraceFlag.FieldOfView.Trace(false, "DQ:   ({0}) from {1}", cone, hexX);
          #endif
        }
        #endregion

        #region Check cone transition
        if (cone.RiseRun > topRiseRun) {
          topVector   = LogAndEnqueue(enqueue, range, topVector, cone.VectorTop, topRiseRun, 5);
          topRiseRun  = cone.RiseRun;
        } else if (cone.RiseRun < topRiseRun) {
          topVector   = LogAndEnqueue(enqueue, range, topVector, overlapVector, topRiseRun, 6);
          topRiseRun  = cone.RiseRun;  // TODO Why is this commented out?
        }
        #endregion

        overlapVector = topVector;
        bottomVector  = cone.VectorBottom;
      } while(true);

      // Pick-up any cone portion at bottom of range still unprocessed
      if (topVector.GT(bottomVector))
        LogAndEnqueue(enqueue, range, topVector, bottomVector, cone.RiseRun, 7);

      return cone;
    }