之前在研究隨機地圖的生成的時候用了一部分點和線之間的關係,部分算法還沒有優化。
List<Line> RandomLines(int count, int x, int y, bool allowIntersect,int bezierControl)
{
List<Line> lines = new List<Line>();
while (lines.Count < count)
{
Line line = RandomLine(x, y, bezierControl);
if ((!isIntersect(line, lines) || allowIntersect) && line.length > 2)
{
lines.Add(line);
}
}
return lines;
}
/// <summary>
/// 獲得一個點周圍的點座標
/// </summary>
/// <param name="center"></param>
/// <param name="bitmap"></param>
/// <param name="distance"></param>
/// <returns></returns>
List<Point> getPointsAround(Point center, Bitmap bitmap, double distance = 1)
{
return getPointsAround(center, bitmap.Width, bitmap.Height, distance);
}
/// <summary>
/// 獲得一個點周圍的點座標
/// </summary>
/// <param name="center"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <param name="distance"></param>
/// <returns></returns>
List<Point> getPointsAround(Point center, int width, int height, double distance = 1)
{
int x = center.X;
int y = center.Y;
List<Point> pointsAround = new List<Point>();
pointsAround.Add(new Point(x - 1, y));
pointsAround.Add(new Point(x + 1, y));
pointsAround.Add(new Point(x, y - 1));
pointsAround.Add(new Point(x, y + 1));
pointsAround.RemoveAll(p => p.X < 0 || p.X >= width || p.Y < 0 || p.Y >= height);
return pointsAround;
}
/// <summary>
/// 獲得點到點羣間的距離
/// </summary>
/// <param name="point"></param>
/// <param name="pointList"></param>
/// <returns></returns>
double getDistanceBetweenPointAndPoints(Point point,List<Point> pointList)
{
double minDistance = 9999999999;
foreach(Point tmp in pointList)
{
minDistance = Math.Min(minDistance, getDistance(point, tmp));
}
return minDistance;
}
/// <summary>
/// 建立一個隨機點
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
Point RandomPoint(int x, int y)
{
return new Point(random.Next(0, x - 1), random.Next(0, y - 1));
}
/// <summary>
/// 添加貝塞爾控制點
/// </summary>
/// <param name="line"></param>
void AddBezierControlPoint(ref Line line,int distance)
{
float k = (line.start.X - (float)line.end.X) / (line.start.Y - (float)line.end.Y);
int xLength = line.end.X - line.start.X;
int yLength = line.end.Y - line.start.Y;
if (Math.Abs(xLength) > Math.Abs(yLength))
{
int randomXLength = xLength > 0 ? random.Next(0, xLength) : random.Next(xLength, 0);
Point controlStart = new Point
{
X = randomXLength + line.start.X,
Y = (int)(randomXLength / k + random.Next(-distance, distance) + line.start.Y)
};
randomXLength = xLength > 0 ? random.Next(0, xLength) : random.Next(xLength, 0);
Point controlEnd = new Point
{
X = randomXLength + line.start.X,
Y = (int)(randomXLength / k + random.Next(-distance, distance) + line.start.Y)
};
line.controlStart = controlStart;
line.controlEnd = controlEnd;
}
else
{
int randomYLength = yLength > 0 ? random.Next(0, yLength) : random.Next(yLength, 0);
line.controlStart = new Point((int)(randomYLength * k + random.Next(-distance, distance) + line.start.X), randomYLength+ line.start.Y);
randomYLength = xLength > 0 ? random.Next(0, xLength) : random.Next(xLength, 0);
line.controlEnd = new Point((int)(randomYLength * k + random.Next(-distance, distance) + line.start.X), randomYLength + line.start.Y);
}
}
/// <summary>
/// 畫一條隨機直線
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
Line RandomLine(int x, int y,int bezierControl)
{
Line line = new Line();
line.start = RandomPoint(x, y);
line.end = RandomPoint(x, y);
AddBezierControlPoint(ref line, bezierControl);
return line;
}
/// <summary>
/// 將貝塞爾曲線畫到圖像上
/// </summary>
/// <param name="line"></param>
void DrawLine(Line line,Bitmap bitmap)
{
GraphicsPath path = new GraphicsPath();
path.AddBezier(line.start, line.controlStart, line.controlEnd, line.end);
Graphics.FromImage(bitmap).DrawPath(Pens.White, path);
}
/// <summary>
/// 將多條貝塞爾曲線畫到圖像上
/// </summary>
/// <param name="lines"></param>
/// <param name="bitmap"></param>
void DrawLines(List<Line> lines,Bitmap bitmap)
{
foreach(Line line in lines)
{
DrawLine(line,bitmap);
}
}
private bool isIntersect(Line line,List<Line> lines)
{
foreach(Line tmpLine in lines)
{
if(isIntersect(line, tmpLine))
{
return true;
}
}
return false;
}
public class Line
{
public Point start;
public Point end;
public Point controlStart;
public Point controlEnd;
public double length
{
get
{
return Math.Sqrt((start.X - end.X) ^ 2 + (start.Y - end.Y) ^ 2);
}
}
}
private double getDistance(Point point1, Point point2)
{
double lineLength = 0;
lineLength = Math.Sqrt((point1.X - point2.X) * (point1.X - point2.X) + (point1.Y - point2.Y) * (point1.Y - point2.Y));
return lineLength;
}
private double pointToLines(List<Line> lines, Point point)
{
double distance = 9999999999;
foreach(Line line in lines)
{
distance = pointToLine(line, point) < distance ? pointToLine(line, point) : distance;
}
return distance;
}
private double pointToLine(Line line, Point point)
{
double space = 0;
double a, b, c;
a = getDistance(line.start, line.end);// 線段的長度
b = getDistance(line.start, point);// (x1,y1)到點的距離
c = getDistance(line.end, point);// (x2,y2)到點的距離
if (c <= 0.000001 || b <= 0.000001)
{
space = 0;
return space;
}
if (a <= 0.000001)
{
space = b;
return space;
}
if (c * c >= a * a + b * b)
{
space = b;
return space;
}
if (b * b >= a * a + c * c)
{
space = c;
return space;
}
double p = (a + b + c) / 2;// 半周長
double s = Math.Sqrt(p * (p - a) * (p - b) * (p - c));// 海倫公式求面積
space = 2 * s / a;// 返回點到線的距離(利用三角形面積公式求高)
return space;
}
/// <summary>
/// 判斷兩條線段是否相交
/// 參考: https://www.cnblogs.com/Kconnie/p/4311745.html
/// </summary>
/// <param name="line1"></param>
/// <param name="line2"></param>
/// <param name="intersection"></param>
/// <returns></returns>
private bool isIntersect(Line line1, Line line2)
{
Point a = line1.start;
Point b = line1.end;
Point c = line2.start;
Point d = line2.end;
Point intersection = new Point();
//判斷異常
if (Math.Abs(b.X - a.Y) + Math.Abs(b.X - a.X) + Math.Abs(d.Y - c.Y) + Math.Abs(d.X - c.X) == 0)
{
if (c.X - a.X == 0)
{
return true;//ABCD是同一個點
}
else
{
return false;//AB是一個點,CD是一個點,且AC不同
}
}
if (Math.Abs(b.Y - a.Y) + Math.Abs(b.X - a.X) == 0)
{
if ((a.X - d.X) * (c.Y - d.Y) - (a.Y - d.Y) * (c.X - d.X) == 0)
{
return true;//A、B是一個點,且在CD線段上
}
else
{
return false;//A、B是一個點,且不在CD線段上
}
}
if (Math.Abs(d.Y - c.Y) + Math.Abs(d.X - c.X) == 0)
{
if ((d.X - b.X) * (a.Y - b.Y) - (d.Y - b.Y) * (a.X - b.X) == 0)
{
return true;//C、D是一個點,且在AB線段上
}
else
{
return false;//C、D是一個點,且不在AB線段上
}
}
if ((b.Y - a.Y) * (c.X - d.X) - (b.X - a.X) * (c.Y - d.Y) == 0)
{
return false;//平行
}
intersection.X = ((b.X - a.X) * (c.X - d.X) * (c.Y - a.Y) - c.X * (b.X - a.X) * (c.Y - d.Y) + a.X * (b.Y - a.Y) * (c.X - d.X)) / ((b.Y - a.Y) * (c.X - d.X) - (b.X - a.X) * (c.Y - d.Y));
intersection.Y = ((b.Y - a.Y) * (c.Y - d.Y) * (c.X - a.X) - c.Y * (b.Y - a.Y) * (c.X - d.X) + a.Y * (b.X - a.X) * (c.Y - d.Y)) / ((b.X - a.X) * (c.Y - d.Y) - (b.Y - a.Y) * (c.X - d.X));
if ((intersection.X - a.X) * (intersection.X - b.X) <= 0 && (intersection.X - c.X) * (intersection.X - d.X) <= 0 && (intersection.Y - a.Y) * (intersection.Y - b.Y) <= 0 && (intersection.Y - c.Y) * (intersection.Y - d.Y) <= 0)
{
return true; //相交
}
else
{
return false; //相交但不在線段上
}
}
private Color getColor(int height,int waterHeight = 35)
{
height = Math.Min(255, height);
height = Math.Max(0, height);
if (height > waterHeight)
return Color.FromArgb(height, height, height);
else
return Color.DarkBlue;
}
/// <summary>
/// 獲取周圍點的平均高度
/// </summary>
/// <param name="center"></param>
/// <param name="bitmap"></param>
/// <param name="minHeight"></param>
/// <param name="distance"></param>
/// <returns></returns>
int getPointsAroundHeight(Point center, Bitmap bitmap, int minHeight, double distance = 1)
{
int height = 0;
List<Point> points = getPointsAround(center, bitmap, distance);
for (int index = 0; index < points.Count; index++)
{
height += bitmap.GetPixel(points[index].X, points[index].Y).R;
}
if (height / points.Count < minHeight)
return height / points.Count;
else
return bitmap.GetPixel(center.X, center.Y).R;
}
/// <summary>
/// 獲取周圍點的平均高度
/// </summary>
/// <param name="center"></param>
/// <param name="bitmap"></param>
/// <param name="distance"></param>
/// <returns></returns>
int getPointsAroundHeight(Point center, Bitmap bitmap, double distance = 1)
{
int height = 0;
List<Point> points = getPointsAround(center, bitmap, distance);
for (int index = 0; index < points.Count; index++)
{
height += bitmap.GetPixel(points[index].X, points[index].Y).R;
}
return height / points.Count;
}
等我過年回來補充註釋,最後祝大家身體健康