Return to Snippet

Revision: 66460
at May 11, 2014 06:49 by omarelsaid


Initial Code
//***************************************************//
Beginning of Rects.hpp file
//***************************************************//
#ifndef HAWKEYERECTANGLES_RECT_H_
#define HAWKEYERECTANGLES_RECT_H_

#include <limits.h>
struct Point
{
    Point() : x(INT_MIN), y(INT_MIN) { }
    Point(int x, int y) : x(x), y(y) { }

    int x;
    int y;
};

//a Rect object is considered to be drawn from the top left corner to the bottom right corner
class Rect
{
public:
    Rect() { }
    Rect(const Point& c1, const Point& c2, const Point& c3, const Point& c4);

    bool isValid() const;
    bool contains(const Point& point) const;
    bool intersects(const Rect& other) const;

    Point tl;
    Point tr;
    Point br;
    Point bl;

private:
    unsigned int countContainedCorners(const Rect& rect, bool& cornerTouchingSide) const;
};

#endif

//***************************************************//
End of Rects.hpp file
//***************************************************//

//***************************************************//
Beginning of Rects.cpp file
//***************************************************//
#include "Rect.hpp"
#include <iostream>
#include <sstream>
#include <fstream>
#include <vector>

Rect::Rect(const Point& c1, const Point& c2, const Point& c3, const Point& c4)
{
    std::vector<Point> corners;
    corners.push_back(c1);
    corners.push_back(c2);
    corners.push_back(c3);
    corners.push_back(c4);
    //set top left and bottom right corners
    tl = c1;
    br = c1;
    for (unsigned int i = 1; i < corners.size(); ++i)
    {
        if (corners[i].x < tl.x || corners[i].y < tl.y)
            tl = corners[i];

        if (corners[i].x > br.x || corners[i].y > br.y)
            br = corners[i];
    }
    //now set top right and bottom left corners
    tr = c1;
    bl = c1;
    for (unsigned int i = 1; i < corners.size(); ++i)
    {
        if (corners[i].x == tl.x && corners[i].y == br.y)
            bl = corners[i];

        if (corners[i].x == br.x && corners[i].y == tl.y)
            tr = corners[i];
    }
}

bool Rect::isValid() const
{
    //checks that all four points are where they should be in respect to each other
    return tl.x == bl.x && tl.y == tr.y && tl.x < tr.x && tl.y < bl.y && br.x == tr.x && br.y == bl.y;
}

bool Rect::contains(const Point& point) const
{
    //checks whether the point in question is within all four sides of the given rectangle
    //NOTE: a corner that is touching a side of the rectangle counts as being inside the rectangle
    return point.x >= tl.x && point.x <= br.x && point.y >= tl.y && point.y <= br.y;
}

bool Rect::intersects(const Rect& other) const
{
    bool cornerTouchingSide = false;
    unsigned int numberOfCornersInRect = countContainedCorners(other, cornerTouchingSide);

    if (0 == numberOfCornersInRect)
        return false;

    // if only 1 or 2 corners of one rect are inside the other, then there's a definite intersection of rectangles
    if (numberOfCornersInRect > 0 && numberOfCornersInRect < 3)
        return true;

    //if all four corners of one rect are inside the other, then at least one contains the other
    //(or they can both contain each other if they're the same rectangle)
    //NOTE: 3 corners of one rectangle being inside the other => all 4 corners are inside, given the nature of rectangles
    //in this case, we need to use the check above if one corner of one rectangle touches a side of the other rectangle
    return cornerTouchingSide;
}

unsigned int Rect::countContainedCorners(const Rect& rect, bool& cornerTouchingSide) const
{
    std::vector<Point> corners;
    corners.push_back(rect.tl);
    corners.push_back(rect.tr);
    corners.push_back(rect.br);
    corners.push_back(rect.bl);

    unsigned int numberOfCornersInRect = 0;
    for (unsigned int i = 0; i < corners.size(); ++i)
    {
        if (contains(corners[i]))
            ++numberOfCornersInRect;

        //check whether this corner has common x or y coordinate with any corner of this rectangle
        //this will mean that at least one corner of one rectangle will be touching a side of the other rectangle
        //this check will be needed later in the case that one rect is contained inside the other
        if (!cornerTouchingSide)
            cornerTouchingSide = corners[i].x == tl.x || corners[i].x == br.x || corners[i].y == tl.y || corners[i].y == br.y;
    }

    if (numberOfCornersInRect != 0)
        return numberOfCornersInRect;

    //search for corners of this rectangle contained within the other rectangle
    //NOTE: no need to set cornerTouchingSide boolean again 
    corners.clear();
    corners.push_back(tl);
    corners.push_back(tr);
    corners.push_back(br);
    corners.push_back(bl);
    for (unsigned int i = 0; i < corners.size(); ++i)
    {
        if (rect.contains(corners[i]))
            ++numberOfCornersInRect;
    }

    return numberOfCornersInRect;
}
//***************************************************//
End of Rects.cpp file
//***************************************************//

//***************************************************//
Beginning of RectIntersections.hpp file
//***************************************************//
#ifndef HAWKEYERECTANGLES_RECTINTERSECTIONS_H_
#define HAWKEYERECTANGLES_RECTINTERSECTIONS_H_

#include "Rect.hpp"
#include <string>
#include <vector>
#include <fstream>

class RectIntersections
{
public:
    RectIntersections(const std::string& rectsFilePath, const std::string& logFilePath = std::string())
        : m_rectsFilePath(rectsFilePath), m_logFilePath(logFilePath) {  }
    bool doAnyTwoRectsIntersect();

private:
    bool extractRectsFromFile(std::vector<Rect>& rects, std::ofstream* log = NULL);

    std::string m_rectsFilePath;
    std::string m_logFilePath;
};

#endif
//***************************************************//
End of RectIntersections.hpp file
//***************************************************//

//***************************************************//
Beginning of RectIntersections.cpp file
//***************************************************//
#include "RectIntersections.hpp"
#include <sstream>
#include <algorithm>

bool RectIntersections::extractRectsFromFile(std::vector<Rect>& rects, std::ofstream* log /*= NULL*/)
{
    std::ifstream ifs(m_rectsFilePath);
    if (!ifs.good())
    {
        if (log)
            *log << "ERROR: The file specified could not be opened for reading or is invalid.";

        return false;
    }

    std::string line;
    while (std::getline(ifs, line))
    {
        std::istringstream isstream(line);
        Point c1, c2, c3, c4;

        isstream >> c1.x >> c1.y >> c2.x >> c2.y >> c3.x >> c3.y >> c4.x >> c4.y;

        Rect rect(c1, c2, c3, c4);
        if (!rect.isValid())
        {
            //user should be notified in the log file if one of the lines in the txt file has resulted in an ill defined rectangle
            if (log)
                *log << "ERROR: The rectangle defined by: '" << line << "' is invalid." << std::endl;

            continue;
        }

        rects.push_back(rect);
    }

    if (rects.empty())
    {
        //user should be notified if there were no rectangles defined in the file input,
        //either because it contained none, and was all writing
        //or perhaps because of too few coordinates to define a rectangle
        if (log)
            *log << "ERROR: There were no well-defined rectangles defined in the file specified." << std::endl;

        return false;
    }

    //if only one rectangle found in file, return false because there is no second rectangle to compare against
    //should not to return true on the basis that the one rect intersects with itself
    if (1 == rects.size())
    {
        if (log)
            *log << "ERROR: Only one well defined rectangle in the file specified was found." << std::endl;

        return false;
    }

    return true;
}

bool RectIntersections::doAnyTwoRectsIntersect()
{
    std::vector<Rect> rects;
    bool extraction;

    if (!m_logFilePath.empty())
    {
        std::ofstream log(m_logFilePath, std::ios_base::app);
        extraction = extractRectsFromFile(rects, &log);
    }
    else
    {
        extraction = extractRectsFromFile(rects);
    }

    if (!extraction)
        return false;

    //now go through each rectangle read in from the file and determine whether any two of them intersect
    for (unsigned int i = 0; i < rects.size(); ++i)
    {
        for (unsigned int j = i + 1; j < rects.size(); ++j)
        {
            if (rects[i].intersects(rects[j]))
                return true;
        }
    }

    return false;
}
//***************************************************//
End of RectIntersections.cpp file
//***************************************************//

Initial URL

                                

Initial Description
This set of files is meant to read in a text file containing 2D coordinates of rectangles on each line, and determine whether any two of them intersect or not.

Initial Title
Rectangle intersections

Initial Tags

                                

Initial Language
C++