尝试通过遍历循环创建x个随机矩形-但不重叠 [英] Trying to create x number of random rectangles by iterating through loop - but no overlapping

查看:159
本文介绍了尝试通过遍历循环创建x个随机矩形-但不重叠的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个被我困住了.这更多的是数学/逻辑问题,而不是特定的JS问题,但是我正在使用的是JS,在某些情况下,我需要将生成的逻辑转换为代码....

我正在尝试在画布上创建X个不重叠的矩形和/或随机大小的正方形,以实现类似此示例图片的效果:

(我想要创建的盒子数量可以在10到100之间变化,可以随意取用.显然,所需的盒子越多,它们都必须越小)

我有一个 JS Fiddle ,在这里我尝试了不同的想法,但是逻辑上这个问题的原因一直在远离我...

我不想要的是经典的斐波那契螺旋盒形图案.我希望可以在某种程度上解决随机性问题,但是我也有这样的想法,我可以每次搜索存储的行数组以找到最长的行,并从该行中的随机点开始.

我正在尝试将画布随机切成两半,然后将该行添加到数组中的当前路径.然后根据第一条线的坐标绘制另一条线,然后再存储该行,依此类推,依此类推……我将坐标存储在这样的对象数组中:

function storeLine(startX, startY, endX, endY, array) {
        array.push({
                start : {
                         x: startX,
                         y: startY
                        },
                end : {
                         x: endX,
                         y: endY
                        }
                });
}

但是我很快遇到了一个问题,那就是我在整个x轴上绘制的第一条线将始终是最长的线,而我最终得到了很多细盒.

在一个理想的世界中,我的最终结果将包含诸如框总数和最小x/y比之类的变量,因此我可以(以某种方式)选择向更多纵向或更多横向框倾斜,以便我可以调整并保持再生,直到获得满意的结果.

无论如何,即使我走在正确的道路上,我也对前进的方向感到困惑.如果有人想继续我目前的道路或采取更好的方法来解决这个问题,那么我将永远背负着您的债!

注意::在检查了我的问题之后,我以为斐波那契盒模式可以作为起点,但是我仍然需要以某种方式制作较大的初始盒被分割成这样,以便当我想要更多的盒子总数时,我不会只是变得越来越小...无论如何,只是一个随机的想法,如果它能给别人带来灵感的话.

其他想法:Voronoi模式也将是惊人的,但是我的数学技能甚至不知道该从哪里开始

解决方案

这是一个很棒的主意!

您可以考虑一下盒子中盒子的术语(也像一棵树).这些框具有自己的坐标和大小.盒子可以在盒子内部,为此,您可以选择一个尺寸(水平或垂直)进行分割,然后分成多个盒子.然后,在每个这些框中可以添加更多框,等等.最后,绘制线条时,只需使框具有绘制自身的能力(并告诉框自己绘制)即可.

下面是一些执行此操作的JS.您可以轻松地进行多少嵌套操作.有点棘手并且可能需要进行一些调整的事情是确定如何将空间分成大致均匀的盒子(有一点点随机差异).我要做的是将空间分成n框,首先要从可用空间的1/n开始,然后再将其随机一点.如果您大多数时候只使用remaining*Math.random(),您最终会得到一个非常狭窄的盒子.

 // probably play around with this to get better splitting
// maybe split near a mouse click
let splitDimension = (l, n) => {
    let splits = [];
    let remaining = l;
    let x = 0;
    for (let i=0; i<n-1; i++) {
        let r = Math.random();
        let seg = remaining * (1/n);
        let s = seg + 0.75*(0.5-r)*seg
        splits.push([x, s]);
        x += s;
        remaining -= s;
    }
    // add the last bit
    splits.push([x, remaining])
    return splits;
};
// the main idea
class Box {
    constructor(x, y, w, h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.boxes = [];
        
    }

    draw(ctx) {
        ctx.beginPath();
        ctx.rect(this.x, this.y, this.w, this.h);
        ctx.stroke();
        this.boxes.forEach(box => {
            box.draw(ctx)
        });
    }

    addBoxes(n, dim) {
        let splits;
        if (dim == "x") {
            // split on width
            splits = splitDimension(this.w, n)
            // turn the splits into new boxes
            this.boxes = splits.map(([x,w]) => {
                return new Box(this.x+x, this.y, w, this.h)
            });
        } else {
            // split over height
            splits = splitDimension(this.h, n);
            this.boxes = splits.map(([y,h]) => {
                return new Box(this.x, this.y+y, this.w, h);
            })
        }
    }
}
let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
// let's make some boxes!
let bigBox = new Box(0,0,canvas.width,canvas.height);
bigBox.addBoxes(2, "y");
// now add boxes on boxes on boxes
bigBox.boxes.forEach(box => {
    box.addBoxes(3, "x");
    // also more boxes
    box.boxes.forEach(boxBox => {
        boxBox.addBoxes(2, "y");
    });
});
// now draw the boxes!
bigBox.draw(ctx);
 

This one has be me stumped. This is more of a Math/logic issue then a specific JS issue, but it's JS that I am working in and and some point I will need to convert the resulting logic to code....

I am trying to create X number of Non-overlapping rectangles and/or squares of random sizes on the canvas to achieve something like this example image:

(the number of boxes I would want to create could range anywhere from 10 to 100, give or take. Obviously the more boxes needed, the smaller they would all have to be)

I have a JS Fiddle where I have been trying different ideas, but the logic of this issue just keeps getting away from me...

What I DONT want is the classic Fibonacci spiral box pattern. I was hoping randomness would take care of that to some degree, but I also had the idea I could search the array of stored lines each time to find the longest line and start from a random point on that line.

I am on the current path of attempting to cut the canvas in half at a random point then add that line to an array. Then draw another lines based on the coordinates of the first line and then store that line also, and so on and so on... I'm storing the coordinates in an array of objects like this:

function storeLine(startX, startY, endX, endY, array) {
        array.push({
                start : {
                         x: startX,
                         y: startY
                        },
                end : {
                         x: endX,
                         y: endY
                        }
                });
}

But I soon hit issues with the fact that the very first line I draw across the whole x axis will ALWAYS be the longest line and I just ended up with lots of thin boxes.

In a perfect world my end result would take in variables like, Total number of boxes and Min x/y ratio so I could (somehow>) have an option to lean towards more portrait or more landscape boxes, so that I could adjust and keep regenerating till I had a result that I liked.

Anyway, I'm stuck about how to proceed, or even if I'm on the right path. If anyone has an idea about to continue down my current path or a better way to go about this, I would be forever in your debt!

Note: after checking my question, I had the thought that the Fibonacci box pattern would be OK as a starting point, but I would somehow still need to make the larger initial boxes also be divided up so that I dont just keep getting smaller and smaller boxes when I want a larger total number of boxes... anyway, just a random thought, if it gives someone else a spark of an idea.

Additional thought: A Voronoi pattern would be amazing too, but my math skills are just not up to even knowing where to start

解决方案

This is a cool idea!

You can think about it terms of boxes in boxes (also like a tree). These boxes have their own coordinates and sizes. Boxes can be inside boxes so to do this you pick a dimension to split on (horizontally or vertically) then divide up for however many boxes. Then in each of those boxes you can add more boxes, etc. Finally to draw the lines you just equip boxes with the ability to draw themselves (and tell their boxes to draw themselves).

Below is some JS that does this. You can play with how much nesting you want to do pretty easily. The thing that is a little tricky and might need some adjusting is determining how to split the space into roughly even boxes (randomly different by a little bit). What's I've done to split the space into n boxes is to start with the size being 1/n of the available space, then randomly nudging it a little. If you just go with remaining*Math.random() most of the time you'll end up with very narrow boxes.

// probably play around with this to get better splitting
// maybe split near a mouse click
let splitDimension = (l, n) => {
    let splits = [];
    let remaining = l;
    let x = 0;
    for (let i=0; i<n-1; i++) {
        let r = Math.random();
        let seg = remaining * (1/n);
        let s = seg + 0.75*(0.5-r)*seg
        splits.push([x, s]);
        x += s;
        remaining -= s;
    }
    // add the last bit
    splits.push([x, remaining])
    return splits;
};
// the main idea
class Box {
    constructor(x, y, w, h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.boxes = [];
        
    }

    draw(ctx) {
        ctx.beginPath();
        ctx.rect(this.x, this.y, this.w, this.h);
        ctx.stroke();
        this.boxes.forEach(box => {
            box.draw(ctx)
        });
    }

    addBoxes(n, dim) {
        let splits;
        if (dim == "x") {
            // split on width
            splits = splitDimension(this.w, n)
            // turn the splits into new boxes
            this.boxes = splits.map(([x,w]) => {
                return new Box(this.x+x, this.y, w, this.h)
            });
        } else {
            // split over height
            splits = splitDimension(this.h, n);
            this.boxes = splits.map(([y,h]) => {
                return new Box(this.x, this.y+y, this.w, h);
            })
        }
    }
}
let canvas = document.querySelector("canvas");
let ctx = canvas.getContext("2d");
// let's make some boxes!
let bigBox = new Box(0,0,canvas.width,canvas.height);
bigBox.addBoxes(2, "y");
// now add boxes on boxes on boxes
bigBox.boxes.forEach(box => {
    box.addBoxes(3, "x");
    // also more boxes
    box.boxes.forEach(boxBox => {
        boxBox.addBoxes(2, "y");
    });
});
// now draw the boxes!
bigBox.draw(ctx);

这篇关于尝试通过遍历循环创建x个随机矩形-但不重叠的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆