覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

矩形同士の交差

左下の座標(X, Y) と 右上の座標(X, Y) が 与えられた矩形(長方形)があったとして、

f:id:nini_y:20190829212551p:plain

2つの矩形が与えられて、その矩形同士が以下のように交差(領域が被っているかを)しているか判定したいです

f:id:nini_y:20190829230458p:plain

交差の判定は

Max(矩形1.左下X, 矩形2.左下X) < Min(矩形1.右上X, 矩形2.右上X) かつ Max(矩形1.左下Y, 矩形2.左下Y) < Min(矩形1.右上Y, 矩形2.右上Y)

で、出来ます。(矩形同士の線分が接しているだけの状態は交差とは呼びにくいと思うので、<= ではなく < で判定しています


一応Javaでプログラム書いてみました。
なんか中途半端な気もしますが・・・

/**
 * 矩形を表現するクラス
 */
public final class Rectangle {

    /** 矩形の左下の点のX */
    private final int lBottomX;

    /** 矩形の左下の点のY */
    private final int lBottomY;

    /** 矩形の右上の点のX */
    private final int rTopX;

    /** 矩形の右上の点のY */
    private final int rTopY;

    public Rectangle(int lBottomX, int lBottomY, int rTopX, int rTopY) {
        // そもそも線や点の表現になってしまう場合は矩形とみなさないものとする
        // 左下と右上の位置関係にならない場合も不正とみなす
        if (lBottomX >= rTopX || lBottomY >= rTopY) {
            throw new IllegalArgumentException("Invalid parameter.");
        }

        this.lBottomX = lBottomX;
        this.lBottomY = lBottomY;
        this.rTopX = rTopX;
        this.rTopY = rTopY;
    }

    /**
     * 引数の矩形と2点が交差するかどうかを判定します
     *
     * @param rec 判定対象の矩形
     * @return 交差する場合true, それ以外の場合false
     */
    public boolean hasIntersect2point(Rectangle rec) {
        return Math.max(lBottomX, rec.lBottomX) < Math.min(rTopX, rec.rTopX) &&
                Math.max(lBottomY, rec.lBottomY) < Math.min(rTopY, rec.rTopY);
    }

    /**
     * 2点が交差する場合の交差している領域を表現する矩形を返します
     *
     * @param rec 判定対象の矩形
     * @return 交差している領域を表現する矩形
     */
    public Rectangle intersect2pointRectangle(Rectangle rec) {
        int maxLBottomX = Math.max(lBottomX, rec.lBottomX);
        int maxLBottomY = Math.max(lBottomX, rec.lBottomY);
        int minRTopX = Math.min(rTopX, rec.rTopX);
        int minRTopY = Math.min(rTopY, rec.rTopY);

        if (!hasIntersect2point(maxLBottomX, minRTopX, maxLBottomY, minRTopY)) {
            throw new IllegalStateException("not intersect 2point.");
        }

        return new Rectangle(maxLBottomX, maxLBottomY, minRTopX, minRTopY);
    }

    private boolean hasIntersect2point(int maxLBottomX, int minRTopX, int maxBottomY, int minRTopY) {
        return maxLBottomX < minRTopX && maxBottomY < minRTopY;
    }

    /**
     * 面積を求める
     *
     * @return 面積
     */
    public int area() {
        return (rTopX - lBottomX) * (rTopY - lBottomY);
    }

    @Override
    public String toString() {
        return "Rectangle{" +
                "lBottomX=" + lBottomX +
                ", lBottomY=" + lBottomY +
                ", rTopX=" + rTopX +
                ", rTopY=" + rTopY +
                ", area=" + area() +
                '}';
    }
}


交差していない矩形同士の場合

矩形同士が離れている場合

public class Main {
    public static void main(String[] args) {
        Rectangle rBase = new Rectangle(2, 2, 6, 5);

        Rectangle r1a = new Rectangle(0, 0, 1, 1);

        System.out.println(""rBase.hasIntersect2point(r1a));        
    }
}


出力結果

false

交差の判定が false になっています


矩形同士のある1辺だけが接していて領域としては重なっていない場合

public class Main {
    public static void main(String[] args) {
        Rectangle rBase = new Rectangle(2, 2, 6, 5);

        Rectangle r1b = new Rectangle(6, 3, 9, 8);

        System.out.println(""rBase.hasIntersect2point(r1b));        
    }
}


出力結果

false

2つの矩形のある辺が重なっている場合も、交差の判定は false になっています


交差する矩形同士の場合

public class Main {
    public static void main(String[] args) {
        Rectangle rBase = new Rectangle(2, 2, 6, 5);

        Rectangle r2 = new Rectangle(1, 1, 3, 4);

        System.out.println(rBase.hasIntersect2point(r2));
        System.out.println(rBase.intersect2pointRectangle(r2));
    }
}


出力結果

true
Rectangle{lBottomX=2, lBottomY=2, rTopX=3, rTopY=4, area=2}


public class Main {
    public static void main(String[] args) {
        Rectangle rBase = new Rectangle(2, 2, 6, 5);

        Rectangle r3 = new Rectangle(3, 3, 4, 4);

        System.out.println(rBase.hasIntersect2point(r3));
        System.out.println(rBase.intersect2pointRectangle(r3));
    }
}


出力結果

true
Rectangle{lBottomX=3, lBottomY=3, rTopX=4, rTopY=4, area=1}


public class Main {
    public static void main(String[] args) {
        Rectangle rBase = new Rectangle(2, 2, 6, 5);

        Rectangle r4 = new Rectangle(3, 3, 6, 7);

        System.out.println(rBase.hasIntersect2point(r4));
        System.out.println(rBase.intersect2pointRectangle(r4));
    }
}


出力結果

true
Rectangle{lBottomX=3, lBottomY=3, rTopX=6, rTopY=5, area=6}


交差の判定が true になって、交差した領域の矩形の情報(座標情報, 面積)が出力されます。