public Wall(Node from, Node to) { From = from; To = to; }
bool PointInPolygon(Node point) { foreach (Wall wall in _walls) { if (IsOnLine(wall.From, wall.To, point)) return true; } bool c = false; foreach (Wall wall in _walls) { Node from = wall.From; Node to = wall.To; if (!IsOnLine(from, to, point) && (from.Y >= point.Y) != (to.Y >= point.Y) && (point.X <= (to.X - from.X) * (point.Y - from.Y) / (to.Y - from.Y) + from.X) ) c = !c; } return c; }
private Wall[] SplitWall(Wall wall, Node node1, Node node2) { Wall[] splitWall = new Wall[2]; if (Equals(wall.From, node1)) { splitWall[0] = new Wall(node2, wall.To); splitWall[1] = null; } else if (Equals(wall.To, node1)) { splitWall[0] = new Wall(wall.From, node2); splitWall[1] = null; } else if (Equals(wall.From, node2)) { splitWall[0] = new Wall(node1, wall.To); splitWall[1] = null; } else if (Equals(wall.To, node2)) { splitWall[0] = new Wall(wall.From, node1); splitWall[1] = null; } else { decimal distanceBetweenFromAndNode1 = (Math.Abs(wall.From.X - node1.X) + Math.Abs(wall.From.Y - node1.Y)) / 2; decimal distanceBetweenFromAndNode2 = (Math.Abs(wall.From.X - node2.X) + Math.Abs(wall.From.Y - node2.Y)) / 2; if (distanceBetweenFromAndNode1 < distanceBetweenFromAndNode2) { splitWall[0] = new Wall(wall.From, node1); splitWall[0] = new Wall(node2, wall.To); } else { splitWall[0] = new Wall(wall.From, node2); splitWall[0] = new Wall(node1, wall.To); } } return splitWall; }
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 IsVisible(Node guard, Node vertex) { if (Equals(guard.X, vertex.X) && Equals(guard.Y, vertex.Y)) return true; foreach (Wall wall in _walls) { if (Intersection(new Segment(wall.From, wall.To), guard, vertex) != null && !IsOnLine(wall.From, wall.To, guard) && !IsOnLine(wall.From, wall.To, vertex) && !IsParallel(new Segment(wall.From, wall.To), new Segment(guard, vertex)) && !Equals(vertex, wall.From) && !Equals(vertex, wall.To)) { return false; } } for (decimal i = (decimal) 0.1; i < 1; i += (decimal) 0.1) { decimal dy = vertex.Y - guard.Y; decimal dx = vertex.X - guard.X; Node point; if (Equals(guard.X, vertex.X)) { decimal diffY = i * dy; point = new Node(guard.X, guard.Y + diffY); } else { decimal diffX = i * dx; decimal diffY = i * dy; point = new Node(guard.X + diffX, guard.Y + diffY); } if (!IsOnLine(vertex, guard, point) && !PointInPolygon(point)) { return false; } } return true; }
private VertexType GetVertexType(Node vertex) { decimal area = GetArea(new[] { GetPrevious(vertex), vertex, GetNext(vertex) }); if (area < 0) return VertexType.Special; if (area > 0) return VertexType.Normal; return VertexType.NotAVertex; }
// 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; }
private Node GetPrevious(Node vertex) { var vertexIndex = _vertices.IndexOf(vertex); if (vertexIndex == 0) return (Node)_vertices[_vertices.Count - 1]; return (Node)_vertices[vertexIndex - 1]; }
private Node GetNext(Node vertex) { var vertexIndex = _vertices.IndexOf(vertex); if (vertexIndex == _vertices.Count - 1) return (Node)_vertices[0]; return (Node)_vertices[vertexIndex + 1]; }
private static decimal GetArea(Node[] vertices) { decimal area = 0; for (int i = 0; i < vertices.Length; i++) { int j = (i + 1) % vertices.Length; area += (vertices[i].X * vertices[j].Y); area -= (vertices[i].Y * vertices[j].X); } return area / 2; }
private static bool Equals(Node n1, Node n2) { if (Math.Abs(n1.X - n2.X) < epsilon && Math.Abs(n1.Y - n2.Y) < epsilon) { return true; } return false; }
public bool IsOnLine(Node endPoint1, Node endPoint2, Node checkPoint) { if ((Equals(checkPoint.X, endPoint1.X) && Equals(checkPoint.Y, endPoint1.Y)) || (Equals(checkPoint.Y, endPoint2.X) && Equals(checkPoint.Y, endPoint2.Y))) { return true; } if (Equals(checkPoint.X - endPoint1.X, 0) && Equals(endPoint2.X - endPoint1.X, 0)) { // vertical line // endPoint1.y < checkpoint.y < endPoint2.y => true // endPoint2.y < checkpoint.y < endPoint1.y => true // else false if ((endPoint1.Y <= checkPoint.Y && checkPoint.Y <= endPoint2.Y) || (endPoint2.Y <= checkPoint.Y && checkPoint.Y <= endPoint1.Y)) { return true; } return false; } try { if ((checkPoint.Y - endPoint1.Y) / (checkPoint.X - endPoint1.X) == (endPoint2.Y - endPoint1.Y) / (endPoint2.X - endPoint1.X)) { // the gradient is the same if ((endPoint1.Y <= checkPoint.Y && checkPoint.Y <= endPoint2.Y) || (endPoint2.Y <= checkPoint.Y && checkPoint.Y <= endPoint1.Y)) { return true; } return false; } } catch (Exception e) { Console.Write(e); } return false; }