Recursion 画出",;“生命的种子”;没有重画任何东西

Recursion 画出",;“生命的种子”;没有重画任何东西,recursion,graphics,Recursion,Graphics,我有一个稍微有趣的问题,我还不能完全弄清楚(虽然公平地说,我喝得很醉) “”是从半径相等的绘图圆创建的图案,以上一个圆的交点为中心 语言并不重要,理论在这里更重要。任何能画圆圈的东西都可以。例如,HTML5+JSCanvas就可以做到这一点。这是递归如何帮助解决问题的一个很好的例子 问题是,一个天真的方法最终会重新画出很多很多圈。有了7个图层,您将获得超过300000个圆形绘图 一种简单的方法是维护以前的圆中心点列表,并且只绘制不在该列表中的圆 我的问题是,是否有“更好”的方法来解决这个问题?不

我有一个稍微有趣的问题,我还不能完全弄清楚(虽然公平地说,我喝得很醉)

“”是从半径相等的绘图圆创建的图案,以上一个圆的交点为中心

语言并不重要,理论在这里更重要。任何能画圆圈的东西都可以。例如,HTML5+JSCanvas就可以做到这一点。这是递归如何帮助解决问题的一个很好的例子

问题是,一个天真的方法最终会重新画出很多很多圈。有了7个图层,您将获得超过300000个圆形绘图

一种简单的方法是维护以前的圆中心点列表,并且只绘制不在该列表中的圆

我的问题是,是否有“更好”的方法来解决这个问题?不需要检查列表的东西


一个值得思考的有趣问题。

多亏了一位朋友,我想我已经解决了这个问题。我将在这里发布我现在正在做的事情,以防有人好奇

简而言之,从中心开始计算六边形的顶点,并将六边形的每条边细分为
i
个位置,其中
i
是层编号

我使用SkiaSharp用C#绘制了它,但是代码对语言来说并没有什么特别之处,没有理由不能用任何语言编写。以下是重要的部分:

const float seedAngle = (float)(Math.PI / 3.0);

static void SeedOfLifeDemo(int x, int y) {
    //setting up Skia stuff, this will be different depending what language you're using.
    var info = new SKImageInfo(x, y);
    using var bitmap = FlatImage(info, SKColors.White);

    SKCanvas canvas = new SKCanvas(bitmap);
    float radius = Math.Min(x, y) / 15;

    SKPoint center = new SKPoint(x / 2f, y / 2f);

    SKPaint strokePaint = new SKPaint {
        Color = SKColors.Black,
        Style = SKPaintStyle.Stroke,
        StrokeWidth = 1,
        IsAntialias = true,
    };

    int layers = 4;
    //Draw the very central circle. This is just a little easier than adding that edge case to SubdividedHexagonAboutPoint
    canvas.DrawCircle(center, radius, strokePaint);
    for (int i = 1; i <= layers; i++) {
        foreach (SKPoint p in SubdividedHexagonAboutPoint(center, radius * i, i)) {
            canvas.DrawCircle(p, radius, strokePaint);
        }
    }
    SaveImage(bitmap, "SeedOfLifeFastDemo.Jpg");//More Skia specific stuff
}

//The magic!
static List<SKPoint> SubdividedHexagonAboutPoint(SKPoint centre, float radius, int subdivisions) {
    List<SKPoint> points = new List<SKPoint>(6 * subdivisions);
    SKPoint? prevPoint = null;
    for (int i = 0; i < 7; i++) {//Step around the circle. The 7th step is to close the last edge
        float x = (float)(Math.Sin(seedAngle * i) * radius + centre.X);
        float y = (float)(Math.Cos(seedAngle * i) * radius + centre.Y);

        SKPoint point = new SKPoint(x, y);
        if (prevPoint != null) {
            points.Add(point);//include the "primary" 6 points
            if (subdivisions > 0) {
                float xDist = (point.X - prevPoint.Value.X) / subdivisions;
                float yDist = (point.Y - prevPoint.Value.Y) / subdivisions;

                for (int sub = 1; sub < subdivisions; sub++) {
                    SKPoint subPoint = new SKPoint(point.X - xDist * sub, point.Y - yDist * sub);
                    points.Add(subPoint);//include the edge subdivisions
                }
            }
        }
        prevPoint = point;
    }
    return points;
}
const float seedAngle=(float)(Math.PI/3.0);
静态无效SeedOfLifeDemo(int x,int y){
//设置Skia工具时,这将根据您使用的语言而有所不同。
var info=新的SKImageInfo(x,y);
使用var bitmap=FlatImage(info,SKColors.White);
SKCanvas canvas=新的SKCanvas(位图);
浮动半径=数学最小值(x,y)/15;
SKPoint中心=新SKPoint(x/2f,y/2f);
SKPaint strokePaint=新SKPaint{
颜色=黑色,
Style=SKPaintStyle.Stroke,
冲程宽度=1,
Isatarias=正确,
};
int层=4;
//画一个非常中心的圆。这比将边的大小写添加到细分的六边形点要简单一点
画布。画圈(中心、半径、笔画);
对于(int i=1;i 0){
浮点xDist=(point.X-prevPoint.Value.X)/细分;
float yDist=(point.Y-prevPoint.Value.Y)/细分;
对于(int sub=1;sub

这确实是一个非常有趣的练习,也是一个例子,说明递归在使用不当时会对您造成伤害。

您不能“保存”当前画布并在该图像上绘制新的圆圈吗?您将需要跟踪以前的圆圈位置,但不必每次都重新绘制。是的,您可以,但这不是真正的问题。问题是,如果每个圆圈周围都有六个“孩子”,那么其中至少有一个会与其邻居的孩子重叠。