public Node FindUnguardedPoint(ArrayList guards) { ArrayList wallsNotVisible = (ArrayList)_walls.Clone(); foreach (Node guard in guards) { ArrayList visibleVertices = new ArrayList(); ArrayList tempWallsNotVisible = (ArrayList)wallsNotVisible.Clone(); foreach (Wall wall in tempWallsNotVisible) { if (wall != null) { bool fromVisible = false, toVisible = false; if (IsVisible(guard, wall.From)) { visibleVertices.Add(wall.From); wall.TemporaryViewablePoint = wall.From; fromVisible = true; } if (IsVisible(guard, wall.To)) { wall.TemporaryViewablePoint = wall.To; toVisible = true; } if (fromVisible && toVisible) { wall.TemporaryViewablePoint = null; //wall.VisibleSegments.Add(new Segment(wall.From, wall.To)); wallsNotVisible.Remove(wall); } } } foreach (Node vertex in visibleVertices) { if (vertex.Type == VertexType.Special) { decimal dy = guard.Y - vertex.Y; decimal dx = guard.X - vertex.X; decimal e = (decimal)0.0000000001; Node nearNode1, nearNode2, distantNode; if (Equals(guard.X, vertex.X)) { decimal diffY = 50 * dy; if (guard.Y < vertex.Y) { nearNode1 = new Node(guard.X, guard.Y + 5 * e); nearNode2 = new Node(vertex.X, vertex.Y + 2 * e); distantNode = new Node(vertex.X, vertex.Y + diffY); } else { nearNode1 = new Node(guard.X, guard.Y - 5 * e); nearNode2 = new Node(vertex.X, vertex.Y - e); distantNode = new Node(vertex.X, vertex.Y - diffY); } } else { decimal deltaX = e * dx; decimal deltaY = e * dy; decimal diffX = 50 * dx; decimal diffY = 50 * dy; if (guard.X < vertex.X) { nearNode1 = new Node(guard.X + deltaX, guard.Y + 5 * deltaY); nearNode2 = new Node(vertex.X + deltaX, vertex.Y + deltaY); distantNode = new Node(vertex.X + diffX, vertex.Y + diffY); } else { nearNode1 = new Node(guard.X - deltaX, guard.Y - 5 * deltaY); nearNode2 = new Node(vertex.X - deltaX, vertex.Y - deltaY); distantNode = new Node(vertex.X - diffX, vertex.Y - diffY); } } if (PointInPolygon(nearNode2) && PointInPolygon(nearNode1)) { Segment extendedLine = new Segment(new Node(guard.X, guard.Y), distantNode); ArrayList intersectionList = new ArrayList(); ArrayList intersectionWallList = new ArrayList(); foreach (Wall wall in _walls) { if (wall != null) { Node intersection = Intersection(extendedLine, wall.From, wall.To); if (intersection != null && !Equals(intersection, vertex)) { intersectionList.Add(intersection); intersectionWallList.Add(wall); } } } Node nearestIntersection = GetNearestIntersection(intersectionList); if (nearestIntersection != null) { Wall wall = intersectionWallList[intersectionList.IndexOf(nearestIntersection)] as Wall; if (wall != null) { if (wall.TemporaryViewablePoint == null) { wall.TemporaryViewablePoint = nearestIntersection; } else { Wall[] splitWall = SplitWall(wall, wall.TemporaryViewablePoint, nearestIntersection); ArrayList tempWallsNotVisible2 = (ArrayList)wallsNotVisible.Clone(); foreach (Wall wallNotVisible in tempWallsNotVisible2) { if (IsOnLine(wallNotVisible.From, wallNotVisible.To, nearestIntersection) && !Equals(nearestIntersection, wall.From) && !Equals(nearestIntersection, wall.To)) { wallsNotVisible.Remove(wall); } } wall.TemporaryViewablePoint = null; wallsNotVisible.Remove(wall); wallsNotVisible.Add(splitWall[0]); if (splitWall[1] != null) wallsNotVisible.Add(splitWall[1]); } } } } } } foreach (Wall wall in wallsNotVisible) { if (wall != null) { wall.TemporaryViewablePoint = null; } } } if (wallsNotVisible.Count == 0) { return new Node(100000, 100000); } foreach (Wall wall in wallsNotVisible) { if (wall != null) { Wall unguardedWall = (Wall)wallsNotVisible[0]; decimal x = (unguardedWall.From.X + unguardedWall.To.X) / 2; decimal y = (unguardedWall.From.Y + unguardedWall.To.Y) / 2; return new Node(x, y); } } return new Node(100000, 100000); }
private bool IsParallel(Segment segment1, Segment segment2) { bool vertical1 = false, vertical2 = false; decimal gradient1 = 0, gradient2 = 0; try { gradient1 = (segment1.To.Y - segment1.From.Y) / (segment1.To.X - segment1.From.X); } catch (Exception) { vertical1 = true; } try { gradient2 = (segment2.To.Y - segment2.From.Y) / (segment2.To.X - segment2.From.X); } catch (Exception) { vertical2 = true; } if (vertical1 && vertical2) { return true; } if (vertical1 || vertical2) { return false; } if (Equals(gradient1, gradient2)) { return true; } return false; }
// TODO: Finish this function private Node Intersection(Segment segment1, Node from, Node to) { if (Equals(segment1.From, from) || Equals(segment1.From, to) || Equals(segment1.To, from) || Equals(segment1.To, to) || IsParallel(segment1, new Segment(from, to))) { return null; } decimal segment1X = segment1.From.X, segment1Y = segment1.From.Y; decimal segment1Dx = segment1.To.X - segment1.From.X, segment1Dy = segment1.To.Y - segment1.From.Y; decimal segment2X = to.X, segment2Y = to.Y; decimal segment2Dx = from.X - to.X, segment2Dy = from.Y - to.Y; if (Equals(segment1Dx, 0) && (from.X < segment1Y && to.X > segment1Y || from.X > segment1Y && to.X < segment1Y)) // Handle segment 1 is vertical { if (Equals(segment1Dx, segment2Dx)) { return null; } decimal gradient = segment2Dy / segment2Dx; Node node = new Node(segment1Y, segment1Y * gradient); if ((node.Y < segment1.From.Y && node.Y < segment1.To.Y) || (node.Y > segment1.From.Y && node.Y > segment1.To.Y)) { return null; } return node; } if (Equals(segment2Dx, 0) && (from.X < segment2Y && to.X > segment2Y || from.X > segment2Y && to.X < segment2Y)) // Handle segment 2 is vertical { if (Equals(segment1Dx, segment2Dx)) { return null; } decimal gradient = segment1Dy / segment1Dx; Node node = new Node(segment2Y, segment2Y * gradient); if ((node.Y < from.Y && node.Y < to.Y) || (node.Y > from.Y && node.Y > to.Y)) { return null; } return node; } if (!Equals(segment2Dx*segment1Dy, segment2Dy*segment1Dx)) { try { decimal t2 = (segment1Dx*(segment2Y - segment1Y) + segment1Dy*(segment1X - segment2X))/ (segment2Dx*segment1Dy - segment2Dy*segment1Dx); decimal t1 = (segment2X + segment2Dx*t2 - segment1X)/segment1Dx; if (t2 <= 1 && t2 >= 0 && t1 >= 0 && t1 <= 1) { Node node = new Node(segment1X + segment1Dx*t1, segment1Y + segment1Dy*t1); /*if (node == from || node == to) // TODO: If intersection is with a concave-inside vertex, ignore it (as above) - return null { if ((Math.Atan2((double)nextDy, (double)nextDx) >= 0 && Math.Atan2((double)previousDy, (double)previousDx) >= 0) || (Math.Atan2((double)nextDy, (double)nextDx) <= 0 && Math.Atan2((double)previousDy, (double)previousDx) <= 0)) { } else { return null; } }*/ return node; } } catch (Exception e) { Console.Write(e); } } return null; }