private void PermissiveFov(int sourceX, int sourceY, permissiveMaskT mask) { fovStateT state = new fovStateT(); state.m_Source = new Point2I(sourceX, sourceY); state.m_Mask = mask; state.m_Board = mask.m_Board; // state.isBlocked = isBlocked; // state.visit = visit; // state.context = context; int quadrantCount = 4; Point2I[] quadrants = { new Point2I(1, 1), new Point2I(-1, 1), new Point2I(-1, -1), new Point2I(1, -1) }; Point2I[] extents = { new Point2I(mask.m_East, mask.m_North), new Point2I(mask.m_West, mask.m_North), new Point2I(mask.m_West, mask.m_South), new Point2I(mask.m_East, mask.m_South) }; int quadrantIndex = 0; for (; quadrantIndex < quadrantCount; ++quadrantIndex) { state.m_Quadrant = quadrants[quadrantIndex]; state.m_Extent = extents[quadrantIndex]; state.m_QuadrantIndex = quadrantIndex; CalculateFovQuadrant(state); } }
private bool ActIsBlocked(fovStateT state, Point2I pos) { Point2I adjustedPos = new Point2I(pos.m_X * state.m_Quadrant.m_X + state.m_Source.m_X, pos.m_Y * state.m_Quadrant.m_Y + state.m_Source.m_Y); if (!state.m_Board.Contains(adjustedPos.m_X, adjustedPos.m_Y)) { return(false);//we are getting outside the board } if (state.m_IsLos || // In LOS calculation all visits allowed state.m_QuadrantIndex == 0 || // can visit anything from Q1 (state.m_QuadrantIndex == 1 && pos.m_X != 0) || // Q2 : no Y axis (state.m_QuadrantIndex == 2 && pos.m_Y != 0) || // Q3 : no X axis (state.m_QuadrantIndex == 3 && pos.m_X != 0 && pos.m_Y != 0)) // Q4 // no X // or Y // axis { if (DoesPermissiveVisit(state.m_Mask, pos.m_X * state.m_Quadrant.m_X, pos.m_Y * state.m_Quadrant.m_Y) == 1) { state.m_Board.Visit(adjustedPos.m_X, adjustedPos.m_Y); } } return(state.m_Board.IsObstacle(adjustedPos.m_X, adjustedPos.m_Y)); }
private void CalculateFovQuadrant(fovStateT state) { LinkedList <bumpT> steepBumps = new LinkedList <bumpT>(); LinkedList <bumpT> shallowBumps = new LinkedList <bumpT>(); // activeFields is sorted from shallow-to-steep. LinkedList <fieldT> activeFields = new LinkedList <fieldT>(); activeFields.AddLast(new fieldT()); activeFields.Last.Value.m_Shallow.m_Near = new Point2I(0, 1); activeFields.Last.Value.m_Shallow.m_Far = new Point2I(state.m_Extent.m_X, 0); activeFields.Last.Value.m_Steep.m_Near = new Point2I(1, 0); activeFields.Last.Value.m_Steep.m_Far = new Point2I(0, state.m_Extent.m_Y); Point2I dest = new Point2I(0, 0); // Visit the source square exactly once (in quadrant 1). if (state.m_Quadrant.m_X == 1 && state.m_Quadrant.m_Y == 1) { ActIsBlocked(state, dest); } CLikeIterator <fieldT> currentField = new CLikeIterator <fieldT>( activeFields.First); int i = 0; int j = 0; int maxI = state.m_Extent.m_X + state.m_Extent.m_Y; // For each square outline for (i = 1; i <= maxI && activeFields.Count > 0; ++i) { int startJ = Max(0, i - state.m_Extent.m_X); int maxJ = Min(i, state.m_Extent.m_Y); // Visit the nodes in the outline for (j = startJ; j <= maxJ && !currentField.IsAtEnd(); ++j) { dest.m_X = i - j; dest.m_Y = j; VisitSquare(state, dest, currentField, steepBumps, shallowBumps, activeFields); } currentField = new CLikeIterator <fieldT>(activeFields.First); } }
private void VisitSquare(fovStateT state, Point2I dest, CLikeIterator <fieldT> currentField, LinkedList <bumpT> steepBumps, LinkedList <bumpT> shallowBumps, LinkedList <fieldT> activeFields) { // The top-left and bottom-right corners of the destination square. Point2I topLeft = new Point2I(dest.m_X, dest.m_Y + 1); Point2I bottomRight = new Point2I(dest.m_X + 1, dest.m_Y); while (!currentField.IsAtEnd() && currentField.GetCurrent().m_Steep .IsBelowOrContains(bottomRight)) { // case ABOVE // The square is in case 'above'. This means that it is ignored // for the currentField. But the steeper fields might need it. currentField.GotoNext(); } if (currentField.IsAtEnd()) { // The square was in case 'above' for all fields. This means that // we no longer care about it or any squares in its diagonal rank. return; } // Now we check for other cases. if (currentField.GetCurrent().m_Shallow.IsAboveOrContains(topLeft)) { // case BELOW // The shallow line is above the extremity of the square, so that // square is ignored. return; } // The square is between the lines in some way. This means that we // need to visit it and determine whether it is blocked. bool isBlocked = ActIsBlocked(state, dest); if (!isBlocked) { // We don't care what case might be left, because this square does // not obstruct. return; } if (currentField.GetCurrent().m_Shallow.IsAbove(bottomRight) && currentField.GetCurrent().m_Steep.IsBelow(topLeft)) { // case BLOCKING // Both lines intersect the square. This current field has ended. currentField.RemoveCurrent(); } else if (currentField.GetCurrent().m_Shallow.IsAbove(bottomRight)) { // case SHALLOW BUMP // The square intersects only the shallow line. AddShallowBump(topLeft, currentField.GetCurrent(), steepBumps, shallowBumps); CheckField(currentField); } else if (currentField.GetCurrent().m_Steep.IsBelow(topLeft)) { // case STEEP BUMP // The square intersects only the steep line. AddSteepBump(bottomRight, currentField.GetCurrent(), steepBumps, shallowBumps); CheckField(currentField); } else { // case BETWEEN // The square intersects neither line. We need to split into two // fields. fieldT steeperField = currentField.GetCurrent(); fieldT shallowerField = new fieldT(currentField.GetCurrent()); currentField.InsertBeforeCurrent(shallowerField); AddSteepBump(bottomRight, shallowerField, steepBumps, shallowBumps); currentField.GotoPrevious(); if (!CheckField(currentField)) // did not remove { currentField.GotoNext(); // point to the original element } AddShallowBump(topLeft, steeperField, steepBumps, shallowBumps); CheckField(currentField); } }