【发布时间】:2016-07-01 18:21:51
【问题描述】:
我正在尝试编写一个脚本,将 100 个不同大小的圆圈放在舞台上。我在下面概述了简洁的要求。
鉴于以下情况:
var stage; // contains a "width" and "height" property.
var circle; // the circle class. contains x, y, radius & a unique id property.
var circleArray; // contains 100 circle instances
要求:
- 编写一个函数,在舞台上放置 100 个不同半径的圆。
- 展示位置必须是随机的,但分布均匀(无聚集)。
- 展示位置必须是高性能的 - 这将在移动网络浏览器上执行。
- 圆圈不得与其他圆圈相交/重叠。
-
circle.x >= 0必须为真。 -
circle.y >= 0 && circle.y <= stage.height必须为真。 - 圆可以具有以下任何半径大小(在创建时分配):
- 150
- 120
- 90
- 80
- 65
我目前的尝试是一种蛮力方法,它不能有效地运行。如果我尝试插入超过 10 个圆圈,浏览器就会挂起。以下是我当前的实现,我完全可以放弃它以支持更高性能/更好的实现。
这是一个现场演示(注意:没有实际的绘图代码,只是逻辑,但它仍然会锁定浏览器,所以请注意!!)http://jsbin.com/muhiziduxu/2/edit?js,console
function adjustForOverlap (circleArray) {
// a reference to the circle that is invoking this function.
var _this = this;
// remove this circle from the array we are iterating over.
var arr = circleArray.filter(function (circle){
return circle.id !== _this.id;
});
// while repeat == true, the circle may be overlapping something.
var repeat = true;
while(repeat) {
var hasOverlap = false;
for (var i=0; i<arr.length; i++) {
var other = arr[i];
var dx = _self.x - other.x;
var dy = _self.y - other.y;
var rr = _self.radius + other.radius;
if (dx * dx + dy * dy < rr * rr) {
// if here, then an overlap was detected.
hit = true;
break;
}
}
// if hit is false, the circle didn't overlap anything, so break.
if (hit === false) {
repeat = false;
break;
} else {
// an overlap was detected, so randomize position.
_self.x = Math.random() * (stage.width*2);
_self.y = Math.random() * stage.height;
}
}
}
【问题讨论】:
-
其实如果空间很小,半径不能为零,可能没有办法解决。这将永远迭代。
-
@Oriol 垂直空间是有限的(即 0 - 500),但是可以根据需要使用尽可能多的水平空间(stage.width * n)
标签: javascript algorithm heuristics