Android如何判断若干个小矩形可不可以被放到一个大矩形中

最近遇到一个问题,如何判断若干个小的矩形可不可以被放到一个大矩形中,小矩形之间不重叠。

举个例子,现在有一个 66 的矩形,我们可不可以在其中放入两个 22 ,两个 23 ,一个 21 和 一个 33 的矩形?
从面积上讲, 222+223+21+33<36 ,但是矩形之间不能有重叠,旋转和变形,那最终能不能放下就不得而知了。

最终得到一个方案就是使用Region

Region有一个好处,可以在上边进行区域的操作,简单来讲就是可以挖各种各样的洞出来。直接上代码吧:


class Widget {
        public Widget(int spanX, int spanY) {
            mSpanX = spanX;
            mSpanY = spanY;
        }
        public boolean mAlreadyPut;
        public int mSpanX; //宽度
        public int mSpanY; //高度
        public Region mRegion = new Region();
    }

    //Region region表示大的区域
private boolean predict(Region region, ArrayList<Widget> widgets, int level) {
        if (level == widgets.size()) {
            return true;
        }
        Rect rect = new Rect();
        for (int i = 0; i < widgets.size(); i++) {
            Widget widget = widgets.get(i);
            if (!widget.mAlreadyPut) {
                widget.mAlreadyPut = true;
                RegionIterator regionIterator = new RegionIterator(region);
                while (regionIterator.next(rect)) {
                    if (rect.right - rect.left >= widget.mSpanX && rect.bottom - rect.top >= widget.mSpanY) {
                        widget.mRegion.set(rect.left, rect.top, rect.left + widget.mSpanX, rect.top + widget.mSpanY);
                        region.op(widget.mRegion, Region.Op.DIFFERENCE);
                        boolean ret = predict(region, widgets, level + 1);
                        if (ret) {
                            return true;
                        }
                        region.op(widget.mRegion, Region.Op.UNION);
                    }
                }
                widget.mAlreadyPut = false;
            }
        }
        return false;
    }

简单解释一下,这个算法是通过递归的方式来判断的,将一个矩形放下后,设置它的mAlreadyPut为true,然后将它的region从大的region中裁剪出去,用这个“带着洞”的region进行递归。
中间涉及到RegionIterator,它是用来遍历一个Region,返回其中包含的矩形,如果其中的某一个矩形可以容纳我们将要放下的矩形,则可以在其中放置。


RegionIterator

一个带着洞的Region,是如何返回它里面包含的矩形区域的,这个是一个问题,如名字所示,它是一个Iterator,那遍历出来的这些矩形,到底是什么样子的是一个未知。如下图,左上角有个小矩形被裁剪出来,剩余区域到底是如何返回矩形,这是个问题。

这里写图片描述

我看了一下代码,不过region的代码进入到了skia库中,太长了,没有继续分析,不过做实验测试一下开始可以的。于是写了个小程序:

public class RegionImageView extends ImageView {

    public RegionImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    Region mRegion = new Region();
    Rect mRect = new Rect();
    Paint mPaint = new Paint();
    Region mCut = new Region();
    Region mCut1 = new Region();
    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        getDrawingRect(mRect);
        mRegion.set(mRect);
        mCut.set(0,0,600,600);
        mCut1.set(0,600,800,1000);
        mRegion.op(mCut, Region.Op.DIFFERENCE);
        mRegion.op(mCut1, Region.Op.DIFFERENCE);
        RegionIterator regionIterator = new RegionIterator(mRegion);
        while (regionIterator.next(mRect)) {
            Log.d("RegionImageView", mRect.toString());
            setRandomColorToPaint();
            canvas.drawRect(mRect, mPaint);
        }
    }

    private void setRandomColorToPaint() {
        int color = Color.argb(255, (int)(Math.random() * 255), (int)(Math.random() * 255), (int)(Math.random() * 255));
        Log.d("RegionImageView", "color:"+color);
        mPaint.setColor(color);
        mPaint.setStyle(Paint.Style.FILL);
    }
}

这里写图片描述

可以看到运行结果,我们可以猜测,Iterator取区域的时候,是让从上到下,x轴的长度一致的一块矩形,没有重叠。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值