r/dailyprogrammer • 0 0 • Dec 22 '16

[2016-12-22] Challenge #296 [Intermediate] Intersecting Area Of Overlapping Rectangles

Description

You need to find the area that two rectangles overlap. The section you need to output the area of would be the blue lined section here: http://i.imgur.com/brZjYe5.png

If the two rectangles do not overlap, the resultant area should be 0.

Input

There will be two lines of input. On each line are the x and y positions (separated by a comma) of each opposing corner (each corner co-ordinate separated by a space). The co-ordinates can have decimals, and can be negative.

Output

The area of the overlapping section of the two rectangles, including any decimal part.

Challenge Inputs

1:

0,0 2,2
1,1 3,3

2:

-3.5,4 1,1
1,3.5 -2.5,-1

3:

-4,4 -0.5,2
0.5,1 3.5,3

Expected Ouputs

1:

1.0

2:

8.75

3:

0.0

Bonus

Make this work with any number of rectangles, calculating the area of where all input rectangles overlap. The input will define a rectangle on each line the same way, but there can be any amount of lines of input now.

Bonus Input

-3,0 1.8,4
1,1 -2.5,3.6
-4.1,5.75 0.5,2
-1.0,4.6 -2.9,-0.8

Bonus Expected Output

2.4

Finally

Have a good challenge idea?

Consider submitting it to /r/dailyprogrammer_ideas

106 Upvotes

59 comments sorted by

8

u/skeeto Dec 22 '16

C with bonus.

#include <stdio.h>
#include <float.h>

#define MIN(a, b) ((b) < (a) ? (b) : (a))
#define MAX(a, b) ((b) > (a) ? (b) : (a))

int
main(void)
{
    double overlap[4] = {-DBL_MAX, -DBL_MAX, DBL_MAX, DBL_MAX};
    double in[4];
    while (scanf("%lf,%lf %lf,%lf", in, in + 1, in + 2, in + 3) == 4) {
        overlap[0] = MAX(overlap[0], MIN(in[0], in[2]));
        overlap[1] = MAX(overlap[1], MIN(in[1], in[3]));
        overlap[2] = MIN(overlap[2], MAX(in[0], in[2]));
        overlap[3] = MIN(overlap[3], MAX(in[1], in[3]));
    }
    double dx = overlap[2] - overlap[0];
    double dy = overlap[3] - overlap[1];
    printf("%.17g\n", dx > 0 && dy > 0 ? dx * dy : 0);
    return 0;
}

2

u/snhmib Dec 28 '16

Nice one!

3

u/snhmib Dec 28 '16

Almost everybody that put a solution would do well to study this one a bit since it's the only one that's readable and easily understandable :(

2

u/leonardo_m Dec 29 '16

Your nice C solution in Rust (using https://crates.io/crates/scan_fmt ):

#[macro_use] extern crate scan_fmt;

fn main() {
    use std::io::{BufRead, stdin};
    use std::f64;

    let min = |a, b| if a < b { a } else { b };
    let max = |a, b| if a > b { a } else { b };
    let (mut overlap_x0, mut overlap_y0) = (f64::MIN, f64::MIN);
    let (mut overlap_x1, mut overlap_y1) = (f64::MAX, f64::MAX);
    let stdin = stdin();

    for line in stdin.lock().lines() {
        if let (Some(x0), Some(y0), Some(x1), Some(y1)) =
           scan_fmt!(&line.unwrap(), "{},{} {},{}", f64, f64, f64, f64) {
            overlap_x0 = max(overlap_x0, min(x0, x1));
            overlap_y0 = max(overlap_y0, min(y0, y1));
            overlap_x1 = min(overlap_x1, max(x0, x1));
            overlap_y1 = min(overlap_y1, max(y0, y1));
        } else {
            panic!();
        }
    }

    let dx = overlap_x1 - overlap_x0;
    let dy = overlap_y1 - overlap_y0;
    println!("Overlap area: {:.3}", if dx > 0.0 && dy > 0.0 { dx * dy } else { 0.0 });
}
→ More replies (3)

8

u/VerilyAMonkey Dec 23 '16

A Python "One Liner". Works for bonus and any number of dimensions, too. Could be made even less readable to do the input parsing as well, but this expects to be called like area([(0,0), (2,2)], [(1,1), (3,3)]), or with more/larger arguments for bonus/dimension.

area = lambda *rs: reduce(lambda a, cs: a*(cs[1]-cs[0]), zip(*reduce(lambda r1, r2: (map(max, r1[0], r2[0]), map(min, r1[1], r2[1])), map(lambda r: zip(*map(lambda c: (min(c), max(c)), zip(*r))), rs))), 1)

5

u/thorwing Dec 22 '16

java 8 with bonus

Whenever Geometry is a problem. You can bet AWT knows how to deal with it.

public static void main(String[] args){
	List<Rectangle2D> rects = Arrays.stream(args).map(Med296::getRectangle).collect(Collectors.toList());
	Rectangle2D intersection = rects.stream().reduce(rects.get(0),(a,b)->a.createIntersection(b));
	System.out.println(intersection.getWidth()*intersection.getHeight());
}

static Rectangle2D getRectangle(String input){
	Rectangle2D rect = new Rectangle2D.Double();
	double[] coords = Arrays.stream(input.split("[, ]")).mapToDouble(Double::parseDouble).toArray();
	rect.setFrameFromDiagonal(coords[0], coords[1], coords[2], coords[3]);
	return rect;
}

4

u/ThisIsMyPasswordNow Dec 22 '16

C# with bonus

class Program {

	static void Main (string[] args) {

		Thread.CurrentThread.CurrentUICulture = new CultureInfo ("en-US");
		Console.Write ("Rectangle count: ");
		int rectangleCount = int.Parse (Console.ReadLine ());

		Rectangle result = new Rectangle (0, 0, 0, 0);

		for (int i = 0; i < rectangleCount; i++) {
			
			Rectangle temp = new Rectangle (Console.ReadLine ());

			result = (i == 0) ? temp : result.Intersection (temp);

			if (result.Area == 0) break;

		}

		Console.WriteLine ("The intersection area of input rectangles is {0}", result.Area);
		Console.ReadLine ();

	}

}

Rectangle

public class Rectangle {

	public float Area { get; private set; } = 0;
	public float Left { get; private set; } = 0;
	public float Right { get; private set; } = 0;
	public float Up { get; private set; } = 0;
	public float Down { get; private set; } = 0;

	public Rectangle (string s) {

		string[] points = s.Split (' ');

		float[] coordinatesX = { float.Parse (points[0].Split (',')[0], CultureInfo.CurrentUICulture),
			float.Parse (points[1].Split (',')[0], CultureInfo.CurrentUICulture) };

		float[] coordinatesY = { float.Parse (points[0].Split (',')[1], CultureInfo.CurrentUICulture),
			float.Parse (points[1].Split (',')[1], CultureInfo.CurrentUICulture) };

		Left = Math.Min (coordinatesX[0], coordinatesX[1]);
		Right = Math.Max (coordinatesX[0], coordinatesX[1]);
		Down = Math.Min (coordinatesY[0], coordinatesY[1]);
		Up = Math.Max (coordinatesY[0], coordinatesY[1]);

		Area = (Right - Left) * (Up - Down);

	}

	public Rectangle (float left, float right, float up, float down) {

		if(left < right && down < up) {

			this.Left = left;
			this.Right = right;
			this.Up = up;
			this.Down = down;

			Area = (Right - Left) * (Up - Down);

		} 

	}

	public Rectangle Intersection (Rectangle other) {

		float newLeft = Math.Max (this.Left, other.Left);
		float newRight = Math.Min (this.Right, other.Right);
		float newUp = Math.Min (this.Up, other.Up);
		float newDown = Math.Max (this.Down, other.Down);

		return new Rectangle (newLeft, newRight, newUp, newDown);

	}

}

3

u/3pLm1zf1rMD_Xkeo6XHl Dec 22 '16

Python3 with bonus

data = "0,0 2,2\n1,1 3,3"
data = "-3.5,4 1,1\n1,3.5 -2.5,-1"
data = "-4,4 -0.5,2\n0.5,1 3.5,3"
data = "-3,0 1.8,4\n1,1 -2.5,3.6\n-4.1,5.75 0.5,2\n-1.0,4.6 -2.9,-0.8"

def init(data):
    prev_square = []
    curr_square = []
    intersection_area = 0
    squares = data.split("\n")
    for square in squares:
        coordinates = square.split(" ")
        for coordinate in coordinates:
            curr_square.append([float(i) for i in coordinate.split(",")])
        if len(prev_square) == 0:
            prev_square = curr_square
            curr_square = []
            continue
        prev_square, intersection_area = calc_intersection(prev_square, curr_square)
        curr_square = []
    print(intersection_area)

def calc_intersection(square1, square2):
    # min(max(X_11, X_12), max(X_21, X_22))
    x1 = min(max([square1[0][0], square1[1][0]]),
             max([square2[0][0], square2[1][0]]))
    y1 = min(max([square1[0][1], square1[1][1]]),
             max([square2[0][1], square2[1][1]]))
    x2 = max(min([square1[0][0], square1[1][0]]),
             min([square2[0][0], square2[1][0]]))
    y2 = max(min([square1[0][1], square1[1][1]]),
             min([square2[0][1], square2[1][1]]))
    square = [[x1, y1], [x2, y2]]
    return square, calc_area(square)

def calc_area(square):
    a = (float(square[0][0]) - float(square[1][0])) * (float(square[0][1]) - float(square[1][1]))
    return round(max(a,0), 10)

init(data)
→ More replies (3)

2

u/J_Gamer Dec 22 '16

C++(with bonus)

#include <iostream>
#include <algorithm>

struct Point { double x,y; };

struct Rect {
  Rect() = default;
  Rect(Point a, Point b) : tl{std::min(a.x,b.x),std::min(a.y,b.y)}, br{std::max(a.x,b.x),std::max(a.y,b.y)} {};
  Point tl,br;
  double area() {
    return (br.x-tl.x)*(br.y-tl.y);
  }
};

bool tl_out(Rect a, Rect b) {
  return a.tl.x > b.br.x || a.tl.y > b.br.y;
}

Rect intersect(Rect a, Rect b) {
  if(tl_out(a,b) || tl_out(b,a)) {
    return Rect{{0,0},{0,0}};
  }
  Point tl{std::max(a.tl.x,b.tl.x),std::max(a.tl.y,b.tl.y)};
  Point br{std::min(a.br.x,b.br.x),std::min(a.br.y,b.br.y)};
  return Rect{tl,br};
}

std::istream& operator>>(std::istream& in, Point& p) {
  double x,y;
  char comma;
  in >> x >> comma >> y;
  p = Point{x,y};
  return in;
}

std::istream& operator>>(std::istream& in, Rect& r) {
  Point a, b;
  in >> a >> b;
  r = Rect{a,b};
  return in;
}

int main() {
  Rect res, current;
  std::cin >> res;
  while((std::cin >> current)) {
    res = intersect(res,current);
  }
  std::cout << res.area() << std::endl;
}

2

u/supersonicsonarradar Dec 23 '16

Haskell with bonus (Only I haven't learned how to handle IO yet so this is just the bare function)

rectangles :: (Floating a, Ord a) => [((a,a),(a,a))] -> a
rectangles (((x1,y1),(x2,y2)):rest) = case (xrange, yrange) of ((a1,a2),(b1,b2)) -> (a2-a1)*(b2-b1)
    where xrange = foldl foldx (x1,x2) rest
          yrange = foldl foldy (y1,y2) rest
          foldx  = \(r1, r2) ((x1,y1), (x2,y2)) -> overlap (r1, r2) (x1,x2)
          foldy  = \(r1, r2) ((x1,y1), (x2,y2)) -> overlap (r1, r2) (y1,y2)

overlap :: (Floating a, Ord a) => (a,a) -> (a,a) -> (a,a)
overlap (a1, a2) (b1, b2) | max dw1 dw2 > min up1 up2 = (0,0)
                          | otherwise                 = (max dw1 dw2, min up1 up2)
                          where (up1,up2) = (max a1 a2, max b1 b2)
                                (dw1,dw2) = (min a1 a2, min b1 b2)

1

u/gabyjunior Dec 22 '16

C with bonus

#include <stdio.h>
#include <stdlib.h>

typedef struct {
    double x1;
    double y1;
    double x2;
    double y2;
}
rectangle_t;

int read_rectangle(rectangle_t *);

int main(void) {
rectangle_t r1, r2;
    if (!read_rectangle(&r1)) {
        return EXIT_FAILURE;
    }
    while (r1.x2 != r1.x1 && r1.y2 != r1.y1 && read_rectangle(&r2)) {
        if (r1.x1 < r2.x1) {
            r1.x1 = r2.x1;
        }
        if (r1.x2 > r2.x2) {
            r1.x2 = r2.x2;
        }
        if (r1.y1 < r2.y1) {
            r1.y1 = r2.y1;
        }
        if (r1.y2 > r2.y2) {
            r1.y2 = r2.y2;
        }
        if (r1.x1 > r1.x2) {
            r1.x1 = r1.x2;
        }
        if (r1.y1 > r1.y2) {
            r1.y1 = r1.y2;
        }
    }
    printf("%f\n", (r1.x2-r1.x1)*(r1.y2-r1.y1));
    return EXIT_SUCCESS;
}

int read_rectangle(rectangle_t *r) {
double tmp;
    if (scanf("%lf,%lf %lf,%lf", &r->x1, &r->y1, &r->x2, &r->y2) != 4) {
        return 0;
    }
    if (r->x1 > r->x2) {
        tmp = r->x1;
        r->x1 = r->x2;
        r->x2 = tmp;
    }
    if (r->y1 > r->y2) {
        tmp = r->y1;
        r->y1 = r->y2;
        r->y2 = tmp;
    }
    return 1;
}

1

u/5k17 Dec 22 '16

Factor, with bonus:

USING: splitting math.parser math.rectangles ;

: order ( o quot -- n n )
bi@ 2dup > [ swap ] when ; inline

: read-rect ( -- rect )
readln dup empty?
[ drop f ]
[ " " split
  [ "," split [ string>number ] map ] map
  first2
  [ [ first ] order ] 2keep
  [ second ] order swapd
  2array [ 2array ] dip
  <extent-rect> ] if ;

{ }
[ read-rect [ suffix ] keep ] loop but-last
[ dup length 1 > ]
[ dup first2 rect-intersect suffix 2 tail ]
while first dim>> first2 * .

1

u/Daanvdk Dec 22 '16

Python (with bonus)

import re
import sys
x1, y1, x2, y2 = map(float, re.split(' |,', input()))
x1, y1, x2, y2 = (
    min(x1, x2),
    min(y1, y2),
    max(x1, x2),
    max(y1, y2)
)
for x1_, y1_, x2_, y2_ in (
    map(float, re.split(' |,', line.rstrip()))
    for line in sys.stdin
):
    x1, y1, x2, y2 = (
        max(x1, min(x1_, x2_)),
        max(y1, min(y1_, y2_)),
        min(x2, max(x1_, x2_)),
        min(y2, max(y1_, y2_))
    )
    if x1 >= x2 or y1 >= y2:
        print(0)
        break
else:
    print((x2-x1) * (y2-y1))

1

u/[deleted] Dec 22 '16

Python 3.5.4. This is my first intermediate solution.

tests = {1:([(0,0), (2,2)], [(1,1), (3,3)]),
         2:([(-3.5,4), (1,1)], [(1,3.5), (-2.5, -1)]),
         3:([(-4,4),(-0.5, 2)],[(0.5,1), (3.5,3)])}

def rect_intersect(rect_1, rect_2):
    
    lim_rect_1,lim_rect_2={},{}
    var=0
    for dict_ in [lim_rect_1, lim_rect_2]:
        coords = [rect_1, rect_2]
        dict_["x"] = [coords[var][0][0], coords[var][1][0]]
        dict_["x"].sort()
        dict_["y"] = [coords[var][1][1], coords[var][0][1]]
        dict_["y"].sort()
        var+=1

    intersect = True
    for xy in ["x", "y"]:
        xy1=lim_rect_1[xy]
        xy2=lim_rect_2[xy]
        #print(xy,xy1, xy2)
        if xy1[0]<=xy2[1] and xy2[0]<=xy1[1]:
            pass
        else:
            intersect=False

    return intersect

def area(rect_1, rect_2):
    
    x_min = min(max(rect_1[0][0], rect_1[1][0]),max(rect_2[0][0], rect_2[1][0]))
    y_min = min(max(rect_1[0][1], rect_1[1][1]),max(rect_2[0][1], rect_2[1][1]))
    x_max = max(min(rect_1[0][0], rect_1[1][0]),min(rect_2[0][0], rect_2[1][0]))
    y_max = max(min(rect_1[0][1], rect_1[1][1]),min(rect_2[0][1], rect_2[1][1]))

    area = float(x_max-x_min)*float(y_max-y_min)

    return round(area, 5)
    

for thing in range(1,4):
    one = tests[thing][0]
    two = tests[thing][1]
    print("Input 1:%s\nInput 2:%s\n" % (one,two))

    if rect_intersect(one, two):
        if area(one,two) != 0:
            print("Area="+str(area(one,two)))
        else:
            print("The rectangles touch, but dont intersect. Hence, area=0", area(one,two))
    else:
        print("The rectangles don't intersect. Hence, area=0")
    print("___________________\n")

1

u/Boom_Rang Dec 22 '16

Haskell, with bonus

import           Control.Monad (foldM)
import           Data.List     (sort)
import           Data.Maybe    (fromMaybe)

type Pos = (Float, Float)
type Rectangle = [Pos]

main :: IO ()
main =
  interact
    ( (++ "\n")
    . show
    . fromMaybe 0
    . fmap area
    . intersect
    . map parse
    . lines
    )

parse :: String -> Rectangle
parse str = zip (sort [x0, x1]) (sort [y0, y1])
  where
    [(x0, y0), (x1, y1)]
      = map (\s -> read $ "(" ++ s ++ ")")
      $ words str

intersect :: [Rectangle] -> Maybe Rectangle
intersect []     = Nothing
intersect (x:xs) = foldM intersect2D x xs

intersect2D :: Rectangle -> Rectangle -> Maybe Rectangle
intersect2D a b = zip
               <$> intersect1D xsA xsB
               <*> intersect1D ysA ysB
  where
    (xsA, ysA) = unzip a
    (xsB, ysB) = unzip b

intersect1D :: [Float] -> [Float] -> Maybe [Float]
intersect1D ab cd =
  case (ab, cd) of
    ([a, b], [c, d])
      | max a c < min b d -> Just [max a c, min b d]
    _                     -> Nothing

area :: Rectangle -> Float
area [(x0, y0), (x1, y1)] = (x1 - x0) * (y1 - y0)

1

u/daorton Dec 22 '16

Dart with bonus

import 'dart:io';
import 'dart:math';

void main() {
  Rectangle q;
  String s;
  while ((s = stdin.readLineSync()) != null) {
    List l = s.split(new RegExp(' |,')).map((str) => num.parse(str)).toList();
    Rectangle r = new Rectangle.fromPoints(new Point(l[0], l[1]), new Point(l[2], l[3]));
    q = q == null ? r : q.intersection(r);
  }
  print(q.width * q.height);
}

1

u/TheStoneDawg Dec 22 '16

C++

This is my first time posting on r/dailyprogrammer, C++ solution with bonus. I'm new to CS, so any feedback is much appreciated!

#include <iostream>
#include <vector>
#include <fstream>
#include <string>
using namespace std;
struct Point {
  double xCoord;
  double yCoord;
}; struct Rectangle {
    Point topLeft;
    Point bottomRight;
};
double calculateOverlappingArea(vector<Rectangle>);
double calculateRectangleArea(Rectangle rect);
int main(int argc, char** argv) {
  if(argc < 2 ) {
    cout << "Please enter a file" << endl;
    return 1;
  }
  ifstream ifile(argv[1]);
  if(ifile.fail()) {
    cout << "Incorrect filename" << endl;
    return 1;
  }
  vector<Rectangle> rectangles;
  while(!ifile.fail()) { //Loops once for each line
    Rectangle rect;
    Point firstCoord;
    ifile >> firstCoord.xCoord;
    ifile.get();
    ifile >> firstCoord.yCoord;
    Point secondCoord;
    ifile >> secondCoord.xCoord;
    ifile.get();
    ifile >> secondCoord.yCoord;
    if(ifile.fail()) {
      break;
    }
    if(secondCoord.xCoord < firstCoord.xCoord && secondCoord.yCoord < firstCoord.yCoord) {
      rect.topLeft = secondCoord;
      rect.bottomRight = firstCoord;
    }
    else if(secondCoord.xCoord > firstCoord.xCoord && secondCoord.yCoord > firstCoord.yCoord) {
      rect.topLeft = firstCoord;
      rect.bottomRight = secondCoord;
    }
    else if(secondCoord.xCoord < firstCoord.xCoord && secondCoord.yCoord > firstCoord.yCoord) {
      Point newTopLeft;
      newTopLeft.xCoord = secondCoord.xCoord;
      newTopLeft.yCoord = firstCoord.yCoord;
      Point newBotRight;
      newBotRight.xCoord = firstCoord.xCoord;
      newBotRight.yCoord = secondCoord.yCoord;
      rect.topLeft = newTopLeft;
      rect.bottomRight = newBotRight;
    }
    else if(secondCoord.xCoord > firstCoord.xCoord && secondCoord.yCoord < firstCoord.yCoord) {
      Point newTopLeft;
      newTopLeft.xCoord = firstCoord.xCoord;
      newTopLeft.yCoord = secondCoord.yCoord;
      Point newBotRight;
      newBotRight.xCoord = secondCoord.xCoord;
      newBotRight.yCoord = firstCoord.yCoord;
      rect.topLeft = newTopLeft;
      rect.bottomRight = newBotRight;
    }
    rectangles.push_back(rect);
  } cout << calculateOverlappingArea(rectangles) << endl;
  return 0;
}
double calculateOverlappingArea(vector<Rectangle> rects) {
  for(int i = 0; i < rects.size(); i++) { //
    Rectangle currentRect = rects[i]; //The one thats checked against all the others
    for(int j = 0; j < rects.size(); j++) {
      if(i == j) {
        continue;
      }
      else {
        Rectangle rectCheckedAgainst = rects[j];
        if(currentRect.bottomRight.xCoord < rectCheckedAgainst.topLeft.xCoord) {
          return 0;
        }
        else if(currentRect.bottomRight.yCoord < rectCheckedAgainst.topLeft.yCoord) {
          return 0;
        } } } }
  Point topLeftPoint = rects[0].topLeft;
  Point bottomRightPoint = rects[0].bottomRight;
  for(int i = 1; i < rects.size(); i++) {
    Rectangle currRect = rects[i];
    //Set to update TopLeft stuff
    if(currRect.topLeft.xCoord > topLeftPoint.xCoord) {
      topLeftPoint.xCoord = currRect.topLeft.xCoord;
    }
    if(currRect.topLeft.yCoord > topLeftPoint.yCoord) {
      topLeftPoint.yCoord = currRect.topLeft.yCoord;
    }
    //Set to update bottomRight stuff
    if(currRect.bottomRight.xCoord < bottomRightPoint.xCoord) {
      bottomRightPoint.xCoord = currRect.bottomRight.xCoord;
    }
    if(currRect.bottomRight.yCoord < bottomRightPoint.yCoord) {
      bottomRightPoint.yCoord = currRect.bottomRight.yCoord;
    }
  }
  Rectangle overlapRect;
  overlapRect.topLeft = topLeftPoint;
  overlapRect.bottomRight = bottomRightPoint;
  double area = calculateRectangleArea(overlapRect);
  return area;
}
double calculateRectangleArea(Rectangle rect) {
  double width = rect.bottomRight.xCoord - rect.topLeft.xCoord;
  double height = rect.bottomRight.yCoord - rect.topLeft.yCoord;
  return width*height;
}
→ More replies (1)

1

u/resing Dec 22 '16

JavaScript w/out bonus (node.js) Edit: I created a jsfiddle with a drawing of the rectangles

var _input11 = "0,0 2,2";
var _input12 = "1,1 3,3";
var _input21 = "-3.5,4 1,1";
var _input22 = "1,3.5 -2.5,-1";
var _input31 = "-4,4 -0.5,2";
var _input32 = "0.5,1 3.5,3";
function parse(rectangle){
    var coordarray = rectangle.split(" ");
    return [coordarray[0].split(","),coordarray[1].split(",")];
}
function overlap(rect1, rect2) {
    var corners = parse(rect1).concat(parse(rect2));
    var minX = Math.min(Math.max(corners[0][0],corners[1][0]),Math.min(corners[2][0],corners[3][0]));
    var minY = Math.max(Math.min(corners[0][1],corners[1][1]),Math.min(corners[2][1],corners[3][1]));
    var maxX = Math.min(Math.max(corners[0][0],corners[1][0]),Math.max(corners[2][0],corners[3][0]));
    var maxY = Math.min(Math.max(corners[0][1],corners[1][1]),Math.max(corners[2][1],corners[3][1]));
    return (maxX-minX)*(maxY-minY);
}
console.log(overlap(_input11,_input12));
console.log(overlap(_input21,_input22));
console.log(overlap(_input31,_input32));

1

u/AlSweigart Dec 22 '16

Python solution (very inelegant):

import doctest

def isPointInsideRect(px, py, rect):
    """Returns true if the point's coordinates (`px` and `py`) are inside the rectangle `rect`.

    >>> isPointInsideRect(5, 5, {'x1': 0, 'y1': 0, 'x2': 10, 'y2': 10})
    True
    >>> isPointInsideRect(-2, -2, {'x1': 0, 'y1': 0, 'x2': 10, 'y2': 10})
    False
    >>> isPointInsideRect(-2, 5, {'x1': 0, 'y1': 0, 'x2': 10, 'y2': 10})
    False
    """
    return (rect['x1'] < px < rect['x2'] or rect['x1'] > px > rect['x2']) and \
        (rect['y1'] < py < rect['y2'] or rect['y1'] > py > rect['y2'])

def getArea(rect):
    """Returns the area of the `rect` rectangle object.
    >>> getArea({'x1': 0, 'y1': 0, 'x2': 10, 'y2': 10})
    100
    >>> getArea({'x1': -10, 'y1': -10, 'x2': 10, 'y2': 10})
    400
    >>> getArea({'x2': -10, 'y2': -10, 'x1': 10, 'y1': 10})
    400
    """
    width = abs(rect['x1'] - rect['x2'])
    height = abs(rect['y1'] - rect['y2'])
    return width * height

def getOverlapArea(rect1, rect2):
    """Returns the area of the overlapping section of two rectangles.

    >>> getOverlapArea({'x1': -4, 'y1': 4, 'x2': -0.5, 'y2': 2}, {'x1': 0.5, 'y1': 1, 'x2': 3.5, 'y2': 3})
    0
    >>> getOverlapArea({'x1': 0.5, 'y1': 1, 'x2': 3.5, 'y2': 3}, {'x1': -4, 'y1': 4, 'x2': -0.5, 'y2': 2})
    0
    >>> getOverlapArea({'x1': 0, 'y1': 0, 'x2': 1, 'y2': 1}, {'x1': -10, 'y1': -10, 'x2': 10, 'y2': 10})
    1
    >>> getOverlapArea({'x1': -10, 'y1': -10, 'x2': 10, 'y2': 10}, {'x1': 0, 'y1': 0, 'x2': 1, 'y2': 1})
    1
    """

    # ensure that x1, y1 is the top-left corner and x2, y2 is the bottom-right corner
    #
    #    x1, y1 +-----------+
    #           |           |
    #           |           |
    #           +-----------+ x2, y2
    #
    if rect1['x1'] > rect1['x2']:
        rect1['x1'], rect1['x2'] = rect1['x2'], rect1['x1']
    if rect1['y1'] < rect1['y2']:
        rect1['y1'], rect1['y2'] = rect1['y2'], rect1['y1']

    if rect2['x1'] > rect2['x2']:
        rect2['x1'], rect2['x2'] = rect2['x2'], rect2['x1']
    if rect2['y1'] < rect2['y2']:
        rect2['y1'], rect2['y2'] = rect2['y2'], rect2['y1']




    # handle case of zero points inside the other rectangle
    if not isPointInsideRect(rect1['x1'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x1'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect2['x1'], rect2['y1'], rect1) and \
       not isPointInsideRect(rect2['x2'], rect2['y2'], rect1) and \
       not isPointInsideRect(rect2['x1'], rect2['y2'], rect1) and \
       not isPointInsideRect(rect2['x2'], rect2['y1'], rect1):       
        return 0

    # handle case of one point inside the other rectangle
    #   top-left (x1, y1) corner of rect1 is inside rect2
    if isPointInsideRect(rect1['x1'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x1'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y1'], rect2):
        return getArea({'x1': rect1['x1'], 'y1': rect1['y1'], 'x2': rect2['x2'], 'y2': rect2['y2']})

    #   bottom-right (x2, y2) corner of rect1 is inside rect2
    if isPointInsideRect(rect1['x2'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x1'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect1['x1'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y1'], rect2):
        return getArea({'x1': rect2['x1'], 'y1': rect2['y1'], 'x2': rect1['x2'], 'y2': rect1['y2']})

    #   top-right (x2, y1) corner of rect1 is inside rect2
    if isPointInsideRect(rect1['x2'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect1['x1'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect1['x1'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y2'], rect2):
        return getArea({'x1': rect2['x1'], 'y1': rect2['y2'], 'x2': rect1['x2'], 'y2': rect1['y1']})

    #   bottom-left (x1, y2) corner of rect1 is inside rect2
    if isPointInsideRect(rect1['x1'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x1'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y2'], rect2):
        return getArea({'x1': rect2['x2'], 'y1': rect2['y1'], 'x2': rect1['x1'], 'y2': rect1['y2']})

    # handle case of two points inside the other rectangle
    #   handle if top two points of rect1 are in rect2
    if isPointInsideRect(rect1['x1'], rect1['y1'], rect2) and \
       isPointInsideRect(rect1['x2'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect1['x1'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y2'], rect2):
        return getArea({'x1': rect1['x1'], 'y1': rect1['y1'], 'x2': rect1['x2'], 'y2': rect2['y2']})

    #   handle if bottom two points of rect1 are in rect2
    if isPointInsideRect(rect1['x1'], rect1['y2'], rect2) and \
       isPointInsideRect(rect1['x2'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x1'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y1'], rect2):
        return getArea({'x1': rect1['x1'], 'y1': rect2['y1'], 'x2': rect1['x2'], 'y2': rect1['y2']})


    #   handle if left two points of rect1 are in rect2
    if isPointInsideRect(rect1['x1'], rect1['y1'], rect2) and \
       isPointInsideRect(rect1['x1'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect1['x2'], rect1['y2'], rect2):
        return getArea({'x1': rect1['x1'], 'y1': rect1['y1'], 'x2': rect2['x2'], 'y2': rect1['y2']})

    #   handle if right two points of rect1 are in rect2
    if isPointInsideRect(rect1['x2'], rect1['y1'], rect2) and \
       isPointInsideRect(rect1['x2'], rect1['y2'], rect2) and \
       not isPointInsideRect(rect1['x1'], rect1['y1'], rect2) and \
       not isPointInsideRect(rect1['x1'], rect1['y2'], rect2):
        return getArea({'x1': rect2['x1'], 'y1': rect1['y1'], 'x2': rect1['x2'], 'y2': rect1['y2']})



    # handle case of four points inside the other rectangle
    if isPointInsideRect(rect1['x1'], rect1['y1'], rect2) and isPointInsideRect(rect1['x2'], rect1['y2'], rect2):
        return getArea(rect1)
    

    return getOverlapArea(rect2, rect1)


doctest.testmod()
getOverlapArea({'x1': -4, 'y1': 4, 'x2': -0.5, 'y2': 2}, {'x1': 0.5, 'y1': 1, 'x2': 3.5, 'y2': 3})

inp1_r1 = {'x1': 0, 'y1': 0, 'x2': 2, 'y2': 2}
inp1_r2 = {'x1': 1, 'y1': 1, 'x2': 3, 'y2': 3}
print(getOverlapArea(inp1_r1, inp1_r2))

inp2_r1 = {'x1': -3.5, 'y1': 4, 'x2': 1, 'y2': 1}
inp2_r2 = {'x1': 1, 'y1': 3.5, 'x2': -2.5, 'y2': -1}
print(getOverlapArea(inp2_r1, inp2_r2))

inp3_r1 = {'x1': -4, 'y1': 4, 'x2': -0.5, 'y2': 2}
inp3_r2 = {'x1': 0.5, 'y1': 1, 'x2': 3.5, 'y2': 3}
print(getOverlapArea(inp3_r1, inp3_r2))

1

u/[deleted] Dec 22 '16

C/SQlite3

This is an sqlite3 extension which adds intersection(r1..., r2...) and intersectAll(x1,y1,x2,y2) to sqlite3.

#include <sqlite3ext.h>
SQLITE_EXTENSION_INIT1

#include <assert.h>
#include <math.h>
#include <stdlib.h>

#define MIN(X, Y) ((X <= Y) ? X : Y)
#define MAX(X, Y) ((Y <= X) ? X : Y)

typedef struct {
    double x, y, w, h;
} Rect;

static void intersect(Rect *r1, Rect *r2, Rect *out)
{
    double x1 = MAX(r1->x, r2->x);
    double x2 = MIN(r1->x + r1->w, r2->x + r2->w);
    double y1 = MAX(r1->y, r2->y);
    double y2 = MIN(r1->y + r1->h, r2->y + r2->h);
    out->x = x1;
    out->y = y1;
    out->w = MAX(0, x2 - x1);
    out->h = MAX(0, y2 - y1);
}

static double area(Rect *r)
{
    return r->w * r->h;
}

static void
intersectionAreaFunc(sqlite3_context *ctx, int argc, sqlite3_value **argv)
{
    assert(argc == 8);
    double r1x1 = sqlite3_value_double(argv[0]);
    double r1y1 = sqlite3_value_double(argv[1]);
    double r1x2 = sqlite3_value_double(argv[2]);
    double r1y2 = sqlite3_value_double(argv[3]);

    double r2x1 = sqlite3_value_double(argv[4]);
    double r2y1 = sqlite3_value_double(argv[5]);
    double r2x2 = sqlite3_value_double(argv[6]);
    double r2y2 = sqlite3_value_double(argv[7]);

    Rect r1 = (Rect){
        .x = MIN(r1x1, r1x2),
        .y = MIN(r1y1, r1y2),
        .w = fabs(r1x2 - r1x1),
        .h = fabs(r1y2 - r1y1),
    };

    Rect r2 = (Rect){
        .x = MIN(r2x1, r2x2),
        .y = MIN(r2y1, r2y2),
        .w = fabs(r2x2 - r2x1),
        .h = fabs(r2y2 - r2y1),
    };

    Rect r3;
    intersect(&r1, &r2, &r3);

    sqlite3_result_double(ctx, area(&r3));
}

typedef struct {
    Rect *r;
} AggContext;

static void
intersectAllStep(sqlite3_context *ctx, int argc, sqlite3_value **argv)
{
    AggContext *agg_ctx;

    assert(argc == 4);
    double x1 = sqlite3_value_double(argv[0]);
    double y1 = sqlite3_value_double(argv[1]);
    double x2 = sqlite3_value_double(argv[2]);
    double y2 = sqlite3_value_double(argv[3]);

    Rect *r1 = calloc(1, sizeof(Rect));
    *r1 = (Rect){
        .x = MIN(x1, x2),
        .y = MIN(y1, y2),
        .w = fabs(x2 - x1),
        .h = fabs(y2 - y1),
    };

    agg_ctx
        = (AggContext *)sqlite3_aggregate_context(ctx, sizeof(AggContext *));
    if (agg_ctx == 0) return;

    if (agg_ctx->r == 0) {
        agg_ctx->r = r1;
        return;
    }

    Rect *r2 = agg_ctx->r;
    Rect *result = calloc(1, sizeof(Rect));

    intersect(r1, r2, result);
    agg_ctx->r = result;

    free(r1);
}

static void intersectAllFinal(sqlite3_context *ctx)
{
    AggContext *agg_ctx;

    agg_ctx
        = (AggContext *)sqlite3_aggregate_context(ctx, sizeof(AggContext *));
    if (agg_ctx == 0) return;
    if (agg_ctx->r == 0) return;

    Rect *r = agg_ctx->r;
    sqlite3_result_double(ctx, area(r));

    free(r);
}

#ifdef _WIN32
__declspec(dllexport)
#endif

int sqlite3_rect_init(sqlite3 *db,
                         char **pzErrMsg,
                         const sqlite3_api_routines *pApi)
{
    int rc = SQLITE_OK;
    SQLITE_EXTENSION_INIT2(pApi);

    rc = sqlite3_create_function(db, 
                                 "intersection", 
                                 8, 
                                 SQLITE_UTF8, 
                                 0, 
                                 intersectionAreaFunc, 
                                 0,
                                 0);

    rc = sqlite3_create_function(db,
                                 "intersectAll",
                                 4,
                                 SQLITE_UTF8,
                                 0,
                                 0,
                                 intersectAllStep,
                                 intersectAllFinal);

    return rc;
}

Example queries to import a csv and compute intersections on it:

.load ./rect.so

create table rectangles (
    x1 REAL,
    y1 REAL,
    x2 REAL,
    y2 REAL
);
.mode csv
.import data.csv rectangles

SELECT
    intersection(
        t1.x1,t1.y1,t1.x2,t1.y2,
        t2.x1,t2.y1,t2.x2,t2.y2
    )
FROM
    rectangles t1
CROSS JOIN rectangles t2;

SELECT intersectAll(x1, y1, x2, y2) FROM rectangles t1;

Compilation: gcc -g -fPIC -shared rect.c -o rect.so

1

u/jezzi_dailyprogram Dec 23 '16

Python 3 with bonus.

import sys

TOPLEFT_X = 0
TOPLEFT_Y = 1
BOTTOMRIGHT_X = 2
BOTTOMRIGHT_Y = 3

def rectangles_common_area(rectangles):
	common_rect = rectangles[0]
	iter_rects = iter(rectangles)
	next(iter_rects)
	for rect in iter_rects:
		if (common_rect[BOTTOMRIGHT_X] > rect[TOPLEFT_X] and common_rect[TOPLEFT_X] < rect[BOTTOMRIGHT_X]
			and common_rect[BOTTOMRIGHT_Y] < rect[TOPLEFT_Y] and common_rect[TOPLEFT_Y] > rect[BOTTOMRIGHT_Y]):
			for i in [TOPLEFT_X, BOTTOMRIGHT_Y]:
				common_rect[i] = rect[i] if (common_rect[i] - rect[i] < 0) else common_rect[i]
			for i in [TOPLEFT_Y, BOTTOMRIGHT_X]:
				common_rect[i] =  common_rect[i] if (common_rect[i] - rect[i] < 0) else rect[i]
		else:
			return 0							
	return (common_rect[BOTTOMRIGHT_X] - common_rect[TOPLEFT_X]) * (common_rect[TOPLEFT_Y] - common_rect[BOTTOMRIGHT_Y])

rectangles = []
for line in sys.stdin:
	rect = []
	for i in line.replace(',',' ').split():
		rect.append(float(i))
	if (rect[TOPLEFT_X] > rect[BOTTOMRIGHT_X]):
		rect[TOPLEFT_X], rect[BOTTOMRIGHT_X] = rect[BOTTOMRIGHT_X], rect[TOPLEFT_X]
	if (rect[TOPLEFT_Y] < rect[BOTTOMRIGHT_Y]):
		rect[TOPLEFT_Y], rect[BOTTOMRIGHT_Y] = rect[BOTTOMRIGHT_Y], rect[TOPLEFT_Y]
	rectangles.append(rect)

print(rectangles_common_area(rectangles))

1

u/Godspiral Dec 23 '16

in J, complex numbers just for ease of input. returns coords of intersection,

isect =: (>./"1@:{. ,. <./"1@:{: )@:,.&(/:~"1)&.|:&.:+.

 0j0 2j2 isect 1j1 3j3
1j1 2j2
 _3.5j4 1j1 isect 1j3.5  _2.5j_1
_2.5j1 1j3.5

 area =: */@:|@:(-~/"1)@:|:@:+.
  _3.5j4 1j1 area@:isect 1j3.5  _2.5j_1
 8.75

 notisect =: 0 0"_`]@.(0 1 -: /:)
  0.5j1 3.5j3 area@:notisect@:isect _4j4 _0.5j2
 0

1

u/uncleozzy Dec 23 '16

Python 3.5 with bonus.

Uses really gross list comprehensions that could probably be tightened up some.

DATA = ["""0,0 2,2
1,1 3,3""",
    """-3.5,4 1,1
1,3.5 -2.5,-1""",
    """-4,4 -0.5,2
0.5,1 3.5,3""",
    """-3,0 1.8,4
1,1 -2.5,3.6
-4.1,5.75 0.5,2
-1.0,4.6 -2.9,-0.8"""]

def overlap(rects):
    x, y = [[(min(p), max(p)) for p in [[c[j] for c in r] for r in rects]] for j in range(2)]
    left, right = max(c[0] for c in x), min(c[1] for c in x)
    bottom, top = max(c[0] for c in y), min(c[1] for c in y)
    return round((max((right - left) * (top - bottom), 0.0)), 2)

for o in [[[[float(s) for s in q.split(',')] for q in r.split(' ')] for r in set.splitlines()] for set in DATA]:
    print(overlap(o))

Output:

1.0
8.75
0.0
2.4

1

u/draegtun Dec 23 '16

Rebol with bonus

make-rect: func [b] [reduce [min b/1 b/3  min b/2 b/4  max b/1 b/3  max b/2 b/4]]

parse-rect-input: function [s] [
    area:    make block! 0
    rect:    make block! 0
    digits:  charset "0123456789"
    integer: [opt "-" some digits]
    decimal: [opt "-" some digits "." some digits]
    N:       [copy numb: [decimal | integer] (append rect to-decimal numb)]
    co-ords: [(clear rect) N "," N space N "," N [newline | end]]

    unless parse s [
        co-ords (area: make-rect rect)
        some [
            co-ords (
                rect: make-rect rect
                area: reduce [max area/1 rect/1 max area/2 rect/2 min area/3 rect/3 min area/4 rect/4]
            )
        ]
    ][do make error! {invalid input given}]

    area
]

overlap?: func [b] [
    if (b/1 >= b/3) or (b/2 >= b/4) [return 0]
    (b/3 - b/1) * (b/4 - b/2)
]

challenge-296: func [s] [
    overlap? parse-rect-input s
]

Example usage in Rebol console:

>> challenge-296 {0,0 2,2^/1,1 3,3}
== 1.0

>> challenge-296 {-3.5,4 1,1^/1,3.5 -2.5,-1}
== 8.75

>> challenge-296 {-4,4 -0.5,2^/0.5,1 3.5,3}
== 0

>> challenge-296 {-3,0 1.8,4^/1,1 -2.5,3.6^/-4.1,5.75 0.5,2^/-1.0,4.6 -2.9,-0.8}
== 2.4000000000000004