arma::vec2 Quad::getEdgePoints(double y) const { // create the horizontal intersection line ParametricLine<> scanLine; scanLine.setFromDirection({1, 0}, {0, y}); // create a line-segment for each side of the quad std::vector<ParametricLine<>> lines = {ParametricLine<>(tl, tr, true), ParametricLine<>(tr, br, true), ParametricLine<>(bl, br, true), ParametricLine<>(bl, tl, true)}; // loop through lines and intersect it with the horizontal scan line std::vector<double> values; for (auto& line : lines) { try { values.push_back(scanLine.intersect(line)[0]); } catch (std::domain_error&) { // did not intersect, ignore } } // only two should intersect if there is a solution if (values.size() != 2) { throw std::domain_error("Could not find the edges points"); } // return the minX and maxX return {std::min(values[0], values[1]), std::max(values[0], values[1])}; }
// Use the raycasting method: any plane (equivalent to a line in 2D, but a plane for programming reasons) // throught the point will intersect an even number of times with edges of the polygon iff the point lies // within the polygon bool Polygon::pointContained(const arma::vec2& p) const{ ParametricLine<2> ray; int intersectionCount = 0; ray.setFromDirection(arma::vec2{1,0}, p, arma::vec2({0,std::numeric_limits<double>::infinity()})); arma::vec2 lastIntersection = {0,0}; bool hadPreviousIntersection = false; for(auto& edge : edges){ try { arma::vec2 intersection = ray.intersect(edge); if(hadPreviousIntersection){ if(arma::norm(intersection - lastIntersection) > 1e-6){ intersectionCount++; } } else { intersectionCount++; } hadPreviousIntersection = true; lastIntersection = intersection; } catch (const std::domain_error& e){ //We didnt intersect with the line! //I know, seems kind of silly to use an exception here, but it works nicely with everything else } } return (intersectionCount % 2) == 1; }