public static List <CustomVector> PlaceAt(CustomVector point, StructureLayoutDef building, CustomVector[][] grid)
        {
            RectUtils.HeightWidthFromLayout(building, out int height, out int width);
            List <CustomVector> doors         = GetDoorsInLayout(building);
            List <CustomVector> doorsAdjusted = new List <CustomVector>();

            for (int i = (int)point.X; i < width + point.X; i++)
            {
                for (int j = (int)point.Y; j < height + point.Y; j++)
                {
                    CellType type = doors.FindAll(d => i == d.X + point.X && j == d.Y + point.Y).Any() ? CellType.DOOR : CellType.BUILDING;
                    if (type == CellType.DOOR)
                    {
                        doorsAdjusted.Add(new CustomVector(i, j));
                    }

                    if (grid[i][j] != null)
                    {
                        grid[i][j].Type = type;
                    }
                    else
                    {
                        grid[i][j] = new CustomVector(i, j, type: type);
                    }
                }
            }

            return(doorsAdjusted);
        }
        /// <summary>
        /// Draw X road
        /// </summary>
        private static void DrawXMainRoad(CustomVector[][] grid, int mapWidth, int mapHeight, int borderDist, Random r)
        {
            CustomVector        v1  = new CustomVector(0, r.Next(borderDist, mapHeight - borderDist));
            CustomVector        v2  = new CustomVector(mapWidth - 1, r.Next(borderDist, mapHeight - borderDist));
            List <CustomVector> all = AStar.Run(v1, v2, grid, true);

            all.Add(v1);

            double y;

            for (int i = 0; i < all.Count; i++)
            {
                CustomVector v = all[i];
                y = i + 1 < all.Count ? all[i + 1].Y : v.Y;
                grid[(int)v.X][(int)v.Y].Type = CellType.MAINROAD;
                if (v.Y == y)
                {
                    grid[(int)v.X][(int)v.Y - 1].Type = CellType.MAINROAD;
                    grid[(int)v.X][(int)v.Y + 1].Type = CellType.MAINROAD;
                }
                else if (v.Y < y)
                {
                    grid[(int)v.X][(int)v.Y - 1].Type = CellType.MAINROAD;
                    grid[(int)v.X][(int)v.Y + 1].Type = CellType.MAINROAD;
                    grid[(int)v.X][(int)v.Y + 2].Type = CellType.MAINROAD;
                }
                else if (v.Y > y)
                {
                    grid[(int)v.X][(int)v.Y - 2].Type = CellType.MAINROAD;
                    grid[(int)v.X][(int)v.Y - 1].Type = CellType.MAINROAD;
                    grid[(int)v.X][(int)v.Y + 1].Type = CellType.MAINROAD;
                }
            }
        }
        /// <summary>
        /// Draw Y road
        /// </summary>
        private static void DrawYMainRoad(CustomVector[][] grid, int mapWidth, int mapHeight, int borderDist, Random r)
        {
            CustomVector        v1  = new CustomVector(r.Next(borderDist, mapWidth - borderDist), 0);
            CustomVector        v2  = new CustomVector(r.Next(borderDist, mapWidth - borderDist), mapHeight - 1);
            List <CustomVector> all = AStar.Run(v1, v2, grid, true);

            all.Add(v1);

            double x;

            for (int i = 0; i < all.Count; i++)
            {
                CustomVector v = all[i];
                x = i + 1 < all.Count ? all[i + 1].X : v.X;
                grid[(int)v.X][(int)v.Y].Type = CellType.MAINROAD;
                if (v.X == x)
                {
                    grid[(int)v.X - 1][(int)v.Y].Type = CellType.MAINROAD;
                    grid[(int)v.X + 1][(int)v.Y].Type = CellType.MAINROAD;
                }
                else if (v.X < x)
                {
                    grid[(int)v.X - 1][(int)v.Y].Type = CellType.MAINROAD;
                    grid[(int)v.X + 1][(int)v.Y].Type = CellType.MAINROAD;
                    grid[(int)v.X + 2][(int)v.Y].Type = CellType.MAINROAD;
                }
                else if (v.X > x)
                {
                    grid[(int)v.X - 2][(int)v.Y].Type = CellType.MAINROAD;
                    grid[(int)v.X - 1][(int)v.Y].Type = CellType.MAINROAD;
                    grid[(int)v.X + 1][(int)v.Y].Type = CellType.MAINROAD;
                }
            }
        }
        public static bool CanPlaceAt(CustomVector point, StructureLayoutDef building, CustomVector[][] grid)
        {
            bool result = true;

            RectUtils.HeightWidthFromLayout(building, out int height, out int width);

            for (int i = (int)point.X - 1; i < width + point.X + 1 && result; i++)
            {
                for (int j = (int)(point.Y - 1); j < height + point.Y + 1 && result; j++)
                {
                    if (IsInBound(i, j, grid.Length, grid[0].Length))
                    {
                        if (grid[i][j] != null && grid[i][j].Type != CellType.NONE)
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
            return(result);
        }
        private static bool InsideCircle(CustomVector center, CustomVector tile, float radius)
        {
            float dx = (float)(center.X - tile.X),
                  dy = (float)(center.Y - tile.Y);
            float distance_squared = dx * dx + dy * dy;

            return(distance_squared <= radius * radius);
        }
Пример #6
0
        public static List <CustomVector> Run(CustomVector start, CustomVector end, CustomVector[][] grid, bool neig8)
        {
            gridCols = grid.Count();
            gridRows = grid[0].Count();

            List <CustomVector> Path       = new List <CustomVector>();
            List <CustomVector> OpenList   = new List <CustomVector>();
            List <CustomVector> ClosedList = new List <CustomVector>();
            List <CustomVector> adjacencies;
            CustomVector        current = start;

            OpenList.Add(start);

            while (OpenList.Count > 0 && !ClosedList.Exists(v => v.X == end.X && v.Y == end.Y))
            {
                current = OpenList[0];
                OpenList.Remove(current);
                ClosedList.Add(current);
                adjacencies = GetAdjacent(current, grid, neig8);

                foreach (CustomVector n in adjacencies)
                {
                    if (!ClosedList.Contains(n) && n.Type != CellType.WATER && n.Type != CellType.BUILDING)
                    {
                        if (!OpenList.Contains(n))
                        {
                            n.Parent           = current;
                            n.DistanceToTarget = (float)(Math.Abs(n.X - end.X) + Math.Abs(n.Y - end.Y));
                            n.Cost             = n.Weight + n.Parent.Cost;
                            OpenList.Add(n);
                            OpenList = OpenList.OrderBy(v => v.F).ToList();
                        }
                    }
                }
            }

            if (!ClosedList.Exists(v => v.X == end.X && v.Y == end.Y))
            {
                KLog.Message($"AStar error: end point not found in ClosedList. Closed list count {ClosedList.Count}. Path wanted from {start} to {end}.");
                return(null);
            }

            CustomVector temp = ClosedList[ClosedList.IndexOf(current)];

            if (temp == null)
            {
                KLog.Message("AStar error: temp is null.");
                return(null);
            }

            while (temp != start && temp != null)
            {
                Path.Add(temp);
                temp = temp.Parent;
            }
            return(Path);
        }
 private static bool InsideCircles(CustomVector tile, float radius, List <CustomVector> allPoints)
 {
     foreach (CustomVector item in allPoints)
     {
         if (InsideCircle(item, tile, radius))
         {
             return(false);
         }
     }
     return(true);
 }
 private bool AwayFromAllField(List <CustomVector> allFields, int distance, CustomVector point)
 {
     foreach (CustomVector customVector in allFields)
     {
         if (customVector.DistanceToPow(point) < Math.Pow(distance, 2))
         {
             return(false);
         }
     }
     return(true);
 }
        public CustomVector(double x, double y, CellType type = CellType.NONE, float weight = 1f, ThingDef plant = null)
        {
            X         = x;
            Y         = y;
            this.Type = type;

            Parent           = null;
            DistanceToTarget = -1f;
            Cost             = 1f;
            Weight           = weight;
            PlantType        = plant;
        }
Пример #10
0
        public static List <CustomVector> GetAdjacent(CustomVector n, CustomVector[][] grid, bool neig8)
        {
            List <CustomVector> temp = new List <CustomVector>();

            int row = (int)n.Y;
            int col = (int)n.X;

            if (row + 1 < gridRows)
            {
                temp.Add(grid[col][row + 1]);
            }
            if (row - 1 >= 0)
            {
                temp.Add(grid[col][row - 1]);
            }
            if (col - 1 >= 0)
            {
                temp.Add(grid[col - 1][row]);
            }
            if (col + 1 < gridCols)
            {
                temp.Add(grid[col + 1][row]);
            }

            if (neig8)
            {
                if (col - 1 >= 0 && row - 1 >= 0)
                {
                    temp.Add(grid[col - 1][row - 1]);
                }
                if (col + 1 < gridCols && row - 1 >= 0)
                {
                    temp.Add(grid[col + 1][row - 1]);
                }
                if (col - 1 >= 0 && row + 1 < gridRows)
                {
                    temp.Add(grid[col - 1][row + 1]);
                }
                if (col + 1 < gridCols && row + 1 < gridRows)
                {
                    temp.Add(grid[col + 1][row + 1]);
                }
            }

            return(temp);
        }
Пример #11
0
        public Triangle(CustomVector point1, CustomVector point2, CustomVector point3)
        {
            Vertices[0] = point1;
            if (!IsCounterClockwise(point1, point2, point3))
            {
                Vertices[1] = point3;
                Vertices[2] = point2;
            }
            else
            {
                Vertices[1] = point2;
                Vertices[2] = point3;
            }

            Vertices[0].AdjacentTriangles.Add(this);
            Vertices[1].AdjacentTriangles.Add(this);
            Vertices[2].AdjacentTriangles.Add(this);
            UpdateCircumcircle();
        }
        /// https://bl.ocks.org/mbostock/raw/dbb02448b0f93e4c82c3/?raw=true
        public static List <CustomVector> Run(int maxTries, int Width, int Height, Random r, CustomVector[][] grid)
        {
            List <CustomVector> points = new List <CustomVector>();
            List <CustomVector> active = new List <CustomVector>();

            /* Initial random point */
            CustomVector p0 = new CustomVector(0, 0);

            grid[(int)p0.X][(int)p0.Y] = p0;
            points.Add(p0);
            active.Add(p0);

            while (active.Count > 0)
            {
                int          random_index = r.Next(active.Count);
                CustomVector p            = active.ElementAt(random_index);

                for (int tries = 1; tries <= maxTries; tries++)
                {
                    /* Pick a random angle */
                    int theta = r.Next(361);
                    /* Pick a random radius between r and 1.5r */
                    int new_radius = r.Next(CGO.radius, (int)(1.5f * CGO.radius));
                    /* Find X & Y coordinates relative to point p */
                    int          pnewx = (int)(p.X + new_radius * Math.Cos(ConvertToRadians(theta)));
                    int          pnewy = (int)(p.Y + new_radius * Math.Sin(ConvertToRadians(theta)));
                    CustomVector pnew  = new CustomVector(pnewx, pnewy);

                    if (IsInBound(pnew, Width, Height, CGO.radius) && InsideCircles(pnew, CGO.radius, points))
                    {
                        points.Add(pnew);
                        active.Add(pnew);
                        break;
                    }
                    else if (tries == maxTries)
                    {
                        active.RemoveAt(random_index);
                    }
                }
            }
            return(points);
        }
 private static bool IsInBound(CustomVector p, int gridWidth, int gridHeight, int radius)
 {
     if (p.X < 0)
     {
         return(false);
     }
     if (p.X >= gridWidth - radius)
     {
         return(false);
     }
     if (p.Y < 0)
     {
         return(false);
     }
     if (p.Y >= gridHeight - radius)
     {
         return(false);
     }
     return(true);
 }
Пример #14
0
        public static IEnumerable <Triangle> Run(IEnumerable <CustomVector> points, double maxX, double maxY)
        {
            CustomVector point0    = new CustomVector(0, 0);
            CustomVector point1    = new CustomVector(0, maxY);
            CustomVector point2    = new CustomVector(maxX, maxY);
            CustomVector point3    = new CustomVector(maxX, 0);
            Triangle     triangle1 = new Triangle(point0, point1, point2);
            Triangle     triangle2 = new Triangle(point0, point2, point3);

            border = new List <Triangle>()
            {
                triangle1, triangle2
            };

            HashSet <Triangle> triangulation = new HashSet <Triangle>(border);

            foreach (CustomVector point in points)
            {
                ISet <Triangle> badTriangles = FindBadTriangles(point, triangulation);
                List <Edge>     polygon      = FindHoleBoundaries(badTriangles);

                foreach (Triangle triangle in badTriangles)
                {
                    foreach (CustomVector vertex in triangle.Vertices)
                    {
                        vertex.AdjacentTriangles.Remove(triangle);
                    }
                }
                triangulation.RemoveWhere(o => badTriangles.Contains(o));

                foreach (Edge edge in polygon.Where(possibleEdge => possibleEdge.Point1 != point && possibleEdge.Point2 != point))
                {
                    Triangle triangle = new Triangle(point, edge.Point1, edge.Point2);
                    triangulation.Add(triangle);
                }
            }
            triangulation.RemoveWhere(t => t.Vertices.ToList().Find(v => v.X == 0 || v.Y == 0 || v.X == maxX || v.Y == maxY) != null);
            return(triangulation);
        }
Пример #15
0
        private void UpdateCircumcircle()
        {
            // https://codefound.wordpress.com/2013/02/21/how-to-compute-a-circumcircle/#more-58
            CustomVector p0 = Vertices[0];
            CustomVector p1 = Vertices[1];
            CustomVector p2 = Vertices[2];
            double       dA = p0.X * p0.X + p0.Y * p0.Y;
            double       dB = p1.X * p1.X + p1.Y * p1.Y;
            double       dC = p2.X * p2.X + p2.Y * p2.Y;

            double aux1 = dA * (p2.Y - p1.Y) + dB * (p0.Y - p2.Y) + dC * (p1.Y - p0.Y);
            double aux2 = -(dA * (p2.X - p1.X) + dB * (p0.X - p2.X) + dC * (p1.X - p0.X));
            double div  = 2 * (p0.X * (p2.Y - p1.Y) + p1.X * (p0.Y - p2.Y) + p2.X * (p1.Y - p0.Y));

            if (div == 0)
            {
                Log.Error(new DivideByZeroException().ToString());
            }

            CustomVector center = new CustomVector(aux1 / div, aux2 / div);

            Circumcenter  = center;
            RadiusSquared = (center.X - p0.X) * (center.X - p0.X) + (center.Y - p0.Y) * (center.Y - p0.Y);
        }
Пример #16
0
        public bool IsPointInsideCircumcircle(CustomVector point)
        {
            double d_squared = (point.X - Circumcenter.X) * (point.X - Circumcenter.X) + (point.Y - Circumcenter.Y) * (point.Y - Circumcenter.Y);

            return(d_squared < RadiusSquared);
        }
Пример #17
0
        private bool IsCounterClockwise(CustomVector point1, CustomVector point2, CustomVector point3)
        {
            double result = (point2.X - point1.X) * (point3.Y - point1.Y) - (point3.X - point1.X) * (point2.Y - point1.Y);

            return(result > 0);
        }
Пример #18
0
        private static ISet <Triangle> FindBadTriangles(CustomVector point, HashSet <Triangle> triangles)
        {
            IEnumerable <Triangle> badTriangles = triangles.Where(o => o.IsPointInsideCircumcircle(point));

            return(new HashSet <Triangle>(badTriangles));
        }
Пример #19
0
 public Edge(CustomVector point1, CustomVector point2)
 {
     Point1 = point1;
     Point2 = point2;
 }
        /// <summary>
        /// Generate a grid, add the preexisting vanilla road if needed. Add main roads. Fill the potential point list, add buildings on grid and fill the origin/layout dictionnary
        /// </summary>
        /// <param name="seed">Seed for Random</param>
        /// <param name="sld">SettlementLayoutDef to get all StructureLayoutDef authorized</param>
        /// <param name="map">The map</param>
        /// <returns></returns>
        public static CustomVector[][] GenerateGrid(int seed, SettlementLayoutDef sld, Map map)
        {
            CGO.currentGenStepMoreInfo = "Generating grid and main road";
            int mapWidth  = Math.Min(map.Size.x, sld.settlementSize.x),
                mapHeight = Math.Min(map.Size.z, sld.settlementSize.z);

            // Search for the smallest sized allowed structure. It will be the radius between potential building spawn points
            CGO.radius = 9999;
            for (int i = 0; i < sld.allowedStructures.Count; i++)
            {
                foreach (StructureLayoutDef item in DefDatabase <StructureLayoutDef> .AllDefsListForReading.FindAll(s => s.tags.Contains(sld.allowedStructuresConverted[i].structureLayoutTag)))
                {
                    RectUtils.HeightWidthFromLayout(item, out int height, out int width);
                    if (height < CGO.radius)
                    {
                        CGO.radius = height;
                    }
                    if (width < CGO.radius)
                    {
                        CGO.radius = width;
                    }
                }
            }
            CGO.radius += 2; // Add to radius to ensure no building touch one another

            // Initialize the grid used for generation
            Random r = new Random(seed);

            CustomVector[][] grid = new CustomVector[mapWidth][];
            for (int i = 0; i < mapWidth; i++)
            {
                grid[i] = new CustomVector[mapHeight];
                for (int j = 0; j < mapHeight; j++)
                {
                    grid[i][j] = new CustomVector(i, j);
                }
            }

            // Exclude non bridgeable cells
            for (int i = 0; i < mapWidth; i++)
            {
                for (int j = 0; j < mapHeight; j++)
                {
                    TerrainDef t = map.terrainGrid.TerrainAt(new IntVec3(CGO.offset.x + i, 0, CGO.offset.y + j));
                    if (t.HasTag("Water") && (t.affordances == null || !t.affordances.Contains(TerrainAffordanceDefOf.Bridgeable)))
                    {
                        grid[i][j].Type = CellType.WATER;
                    }
                }
            }
            // Main roads
            CGO.usePathCostReduction = false; // No path cost reduction for main road, for them to be distinct
            DrawXMainRoad(grid, mapWidth, mapHeight, 15, r);
            DrawYMainRoad(grid, mapWidth, mapHeight, 15, r);
            // If bigger sized settlement, add more main roads
            for (int i = 0; i < mapWidth / 100; i++)
            {
                if (i == 0)
                {
                    DrawXMainRoad(grid, mapWidth, mapHeight, mapWidth / 2, r);
                    DrawYMainRoad(grid, mapWidth, mapHeight, mapHeight / 2, r);
                }
                else
                {
                    DrawXMainRoad(grid, mapWidth, mapHeight, 50, r);
                    DrawYMainRoad(grid, mapWidth, mapHeight, 50, r);
                }
            }
            // Get vanilla world road type and use it if present
            if (CGO.preRoadTypes?.Count > 0)
            {
                for (int i = 0; i < mapWidth; i++)
                {
                    for (int j = 0; j < mapHeight; j++)
                    {
                        TerrainDef t = map.terrainGrid.TerrainAt(new IntVec3(CGO.offset.x + i, 0, CGO.offset.y + j));
                        if (CGO.preRoadTypes.Contains(t))
                        {
                            grid[i][j].Type = CellType.MAINROAD; // Add vanilla generated road to the grid
                        }
                    }
                }
            }
            CGO.usePathCostReduction = true;                                         // Renable path cost reduction

            CGO.vectors = PoissonDiskSampling.Run(50, mapWidth, mapHeight, r, grid); // Get all possible points with radius
            CGO.doors   = BuildingPlacement.Run(sld, grid, 50);                      // Place buildings on grid and add them/their origin into vectStruct
            return(grid);
        }
 public double DistanceTo(CustomVector otherVector)
 {
     return(Math.Sqrt(Math.Pow(X - otherVector.X, 2) + Math.Pow(Y - otherVector.Y, 2)));
 }