1188 lines · 44.3 KB · C++
RawDownload
////  CubeProjectedPolygon.cpp//  libraries/shared/src////  Created by Brad Hefta-Gaub on 06/11/13.//  Copyright 2013 High Fidelity, Inc.////  Distributed under the Apache License, Version 2.0.//  See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "CubeProjectedPolygon.h" #include <algorithm> #include <QtCore/QDebug> #include "GeometryUtil.h"#include "SharedUtil.h"#include "SharedLogging.h" glm::vec2 BoundingRectangle::getVertex(int vertexNumber) const {    switch (vertexNumber) {        case BoundingRectangle::BOTTOM_LEFT:            return corner;        case BoundingRectangle::TOP_LEFT:            return glm::vec2(corner.x, corner.y + size.y);        case BoundingRectangle::BOTTOM_RIGHT:            return glm::vec2(corner.x + size.x, corner.y);        case BoundingRectangle::TOP_RIGHT:            return corner + size;    }    assert(false); // not allowed    return glm::vec2(0,0);} BoundingRectangle BoundingRectangle::topHalf() const {    float halfY = size.y/2.0f;    BoundingRectangle result(glm::vec2(corner.x,corner.y + halfY), glm::vec2(size.x, halfY));    return result;} BoundingRectangle BoundingRectangle::bottomHalf() const {    float halfY = size.y/2.0f;    BoundingRectangle result(corner, glm::vec2(size.x, halfY));    return result;} BoundingRectangle BoundingRectangle::leftHalf() const {    float halfX = size.x/2.0f;    BoundingRectangle result(corner, glm::vec2(halfX, size.y));    return result;} BoundingRectangle BoundingRectangle::rightHalf() const {    float halfX = size.x/2.0f;    BoundingRectangle result(glm::vec2(corner.x + halfX , corner.y), glm::vec2(halfX, size.y));    return result;} bool BoundingRectangle::contains(const BoundingRectangle& box) const {    return ( _set &&                (box.corner.x >= corner.x) &&                (box.corner.y >= corner.y) &&                (box.corner.x + box.size.x <= corner.x + size.x) &&                (box.corner.y + box.size.y <= corner.y + size.y)            );} bool BoundingRectangle::contains(const glm::vec2& point) const {    return ( _set &&                (point.x > corner.x) &&                (point.y > corner.y) &&                (point.x < corner.x + size.x) &&                (point.y < corner.y + size.y)            );} void BoundingRectangle::explandToInclude(const BoundingRectangle& box) {    if (!_set) {        corner = box.corner;        size = box.size;        _set = true;    } else {        float minX = std::min(box.corner.x, corner.x);        float minY = std::min(box.corner.y, corner.y);        float maxX = std::max(box.corner.x + box.size.x, corner.x + size.x);        float maxY = std::max(box.corner.y + box.size.y, corner.y + size.y);        corner.x = minX;        corner.y = minY;        size.x = maxX - minX;        size.y = maxY - minY;    }}  void BoundingRectangle::printDebugDetails(const char* label) const {    qCDebug(shared, "%s _set=%s\n    corner=%f,%f size=%f,%f\n    bounds=[(%f,%f) to (%f,%f)]",            (label ? label : "BoundingRectangle"),            debug::valueOf(_set), (double)corner.x, (double)corner.y, (double)size.x, (double)size.y,            (double)corner.x, (double)corner.y, (double)(corner.x+size.x), (double)(corner.y+size.y));}  long CubeProjectedPolygon::pointInside_calls = 0;long CubeProjectedPolygon::occludes_calls = 0;long CubeProjectedPolygon::intersects_calls = 0;  CubeProjectedPolygon::CubeProjectedPolygon(const BoundingRectangle& box) :    _vertexCount(4),    _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX),    _distance(0){    for (int i = 0; i < _vertexCount; i++) {        setVertex(i, box.getVertex(i));    }}  void CubeProjectedPolygon::setVertex(int vertex, const glm::vec2& point) {    _vertices[vertex] = point;     // keep track of our bounding box    if (point.x > _maxX) {        _maxX = point.x;    }    if (point.y > _maxY) {        _maxY = point.y;    }    if (point.x < _minX) {        _minX = point.x;    }    if (point.y < _minY) {        _minY = point.y;    } } // can be optimized with new pointInside()bool CubeProjectedPolygon::occludes(const CubeProjectedPolygon& occludee, bool checkAllInView) const {     CubeProjectedPolygon::occludes_calls++;     // if we are completely out of view, then we definitely don't occlude!    // if the occludee is completely out of view, then we also don't occlude it    //    // this is true, but unfortunately, we're not quite handling projects in the    // case when SOME points are in view and others are not. So, we will not consider    // occlusion for any shadows that are partially in view.    if (checkAllInView && (!getAllInView() || !occludee.getAllInView())) {        return false;    }     // first check the bounding boxes, the occludee must be fully within the boounding box of this shadow    if ((occludee.getMaxX() > getMaxX()) ||        (occludee.getMaxY() > getMaxY()) ||        (occludee.getMinX() < getMinX()) ||        (occludee.getMinY() < getMinY())) {        return false;    }     // we need to test for identity as well, because in the case of identity, none of the points    // will be "inside" but we don't want to bail early on the first non-inside point    bool potentialIdenity = false;    if ((occludee.getVertexCount() == getVertexCount()) && (getBoundingBox().contains(occludee.getBoundingBox())) ) {        potentialIdenity = true;    }    // if we got this far, then check each vertex of the occludee, if all those points    // are inside our polygon, then the tested occludee is fully occluded    int pointsInside = 0;    for(int i = 0; i < occludee.getVertexCount(); i++) {        bool vertexMatched = false;        if (!pointInside(occludee.getVertex(i), &vertexMatched)) {             // so the point we just tested isn't inside, but it might have matched a vertex            // if it didn't match a vertext, then we bail because we can't be an identity            // or if we're not expecting identity, then we also bail early, no matter what            if (!potentialIdenity || !vertexMatched) {                return false;            }        } else {            pointsInside++;        }    }     // we're only here if all points are inside matched and/or we had a potentialIdentity we need to check    if (pointsInside == occludee.getVertexCount()) {        return true;    }     // If we have the potential for identity, then test to see if we match, if we match, we occlude    if (potentialIdenity) {        return matches(occludee);    }     return false; // if we got this far, then we're not occluded} bool CubeProjectedPolygon::occludes(const BoundingRectangle& boxOccludee) const {    CubeProjectedPolygon testee(boxOccludee);    return occludes(testee);} bool CubeProjectedPolygon::matches(const CubeProjectedPolygon& testee) const {    if (testee.getVertexCount() != getVertexCount()) {        return false;    }    int vertextCount = getVertexCount();    // find which testee vertex matches our first polygon vertex.    glm::vec2 polygonVertex = getVertex(0);    int originIndex = 0;    for(int i = 0; i < vertextCount; i++) {        glm::vec2 testeeVertex = testee.getVertex(i);         // if they match, we found our origin.        if (testeeVertex == polygonVertex) {            originIndex = i;            break;        }    }    // Now, starting at the originIndex, walk the vertices of both the testee and ourselves     for(int i = 0; i < vertextCount; i++) {        glm::vec2 testeeVertex  = testee.getVertex((i + originIndex) % vertextCount);        glm::vec2 polygonVertex = getVertex(i);        if (testeeVertex != polygonVertex) {            return false; // we don't match, therefore we're not the same        }    }    return true; // all of our vertices match, therefore we're the same} bool CubeProjectedPolygon::matches(const BoundingRectangle& box) const {    CubeProjectedPolygon testee(box);    return matches(testee);} bool CubeProjectedPolygon::pointInside(const glm::vec2& point, bool* matchesVertex) const {     CubeProjectedPolygon::pointInside_calls++;     // first check the bounding boxes, the point must be fully within the boounding box of this polygon    if ((point.x > getMaxX()) ||        (point.y > getMaxY()) ||        (point.x < getMinX()) ||        (point.y < getMinY())) {        return false;    }     // consider each edge of this polygon as a potential separating axis    // check the point against each edge    for (int i = 0; i < getVertexCount(); i++) {        glm::vec2 start = getVertex(i);        glm::vec2 end   = getVertex((i + 1) % getVertexCount());        float a = start.y - end.y;        float b = end.x - start.x;        float c = a * start.x + b * start.y;        if (a * point.x + b * point.y < c) {            return false;        }    }     return true;} void CubeProjectedPolygon::printDebugDetails() const {    qCDebug(shared, "CubeProjectedPolygon..."            "    minX=%f maxX=%f minY=%f maxY=%f", (double)getMinX(), (double)getMaxX(), (double)getMinY(), (double)getMaxY());    qCDebug(shared, "    vertex count=%d distance=%f", getVertexCount(), (double)getDistance());    for (int i = 0; i < getVertexCount(); i++) {        glm::vec2 point = getVertex(i);        qCDebug(shared, "    vertex[%d] = %f, %f ", i, (double)point.x, (double)point.y);    }} bool CubeProjectedPolygon::intersects(const BoundingRectangle& box) const {    CubeProjectedPolygon testee(box);    return intersects(testee);} bool CubeProjectedPolygon::intersects(const CubeProjectedPolygon& testee) const {    CubeProjectedPolygon::intersects_calls++;    return intersectsOnAxes(testee) && testee.intersectsOnAxes(*this);} //// Tests the edges of this polygon as potential separating axes for this polygon and the// specified other.//// @return false if the polygons are disjoint on any of this polygon's axes, true if they// intersect on all axes.//// Note: this only works on convex polygons////bool CubeProjectedPolygon::intersectsOnAxes(const CubeProjectedPolygon& testee) const {     // consider each edge of this polygon as a potential separating axis    for (int i = 0; i < getVertexCount(); i++) {        glm::vec2 start = getVertex(i);        glm::vec2 end   = getVertex((i + 1) % getVertexCount());        float a = start.y - end.y;        float b = end.x - start.x;        float c = a * start.x + b * start.y;         // if all vertices fall outside the edge, the polygons are disjoint        // points that are ON the edge, are considered to be "outside"        for (int j = 0; j < testee.getVertexCount(); j++) {            glm::vec2 testeeVertex = testee.getVertex(j);             // in comparison below:            //      >= will cause points on edge to be considered inside            //      >  will cause points on edge to be considered outside             float c2 = a * testeeVertex.x + b * testeeVertex.y;            if (c2 >= c) {                goto CONTINUE_OUTER;            }        }        return false;        CONTINUE_OUTER: ;    }    return true;} bool CubeProjectedPolygon::canMerge(const CubeProjectedPolygon& that) const {     // RIGHT/NEAR    // LEFT/NEAR    if (        (getProjectionType() == that.getProjectionType()) &&        (             getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR) ||             getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)        )       ) {        if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(5)) {            return true;        }        if (getVertex(0) == that.getVertex(1) && getVertex(5) == that.getVertex(4)) {            return true;        }        if (getVertex(2) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) {            return true;        }        if (getVertex(1) == that.getVertex(2) && getVertex(4) == that.getVertex(3)) {            return true;        }    }     // NEAR/BOTTOM    if (        (getProjectionType() == that.getProjectionType()) &&        (             getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM)        )       ) {        if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) {            return true;        }        if (getVertex(5) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) {            return true;        }        if (getVertex(1) == that.getVertex(0) && getVertex(2) == that.getVertex(3)) {            return true;        }        if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(2)) {            return true;        }    }     // NEAR/TOP    if (        (getProjectionType() == that.getProjectionType()) &&        (             getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP)        )       ) {        if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {            return true;        }        if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) {            return true;        }        if (getVertex(4) == that.getVertex(5) && getVertex(3) == that.getVertex(2)) {            return true;        }        if (getVertex(5) == that.getVertex(4) && getVertex(2) == that.getVertex(3)) {            return true;        }    }     // RIGHT/NEAR & NEAR/RIGHT/TOP    // LEFT/NEAR  & NEAR/LEFT/TOP    if (            ((getProjectionType()     == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&            (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))            ||            ((getProjectionType()     == (PROJECTION_LEFT  | PROJECTION_NEAR | PROJECTION_TOP)) &&            (that.getProjectionType() == (PROJECTION_LEFT  | PROJECTION_NEAR)))        )    {        if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {            return true;        }    }    // RIGHT/NEAR & NEAR/RIGHT/TOP    // LEFT/NEAR  & NEAR/LEFT/TOP    if (            ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP)) &&            (getProjectionType()       == (PROJECTION_RIGHT | PROJECTION_NEAR)))            ||            ((that.getProjectionType() == (PROJECTION_LEFT  | PROJECTION_NEAR | PROJECTION_TOP)) &&            (getProjectionType()       == (PROJECTION_LEFT  | PROJECTION_NEAR)))         )    {        if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {            return true;        }    }     // RIGHT/NEAR & NEAR/RIGHT/BOTTOM    // NEAR/LEFT & NEAR/LEFT/BOTTOM    if (            ((that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&            (getProjectionType()       == (PROJECTION_RIGHT | PROJECTION_NEAR)))            ||            ((that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&            (getProjectionType()       == (PROJECTION_LEFT | PROJECTION_NEAR)))         )    {        if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) {            return true;        }    }    // RIGHT/NEAR & NEAR/RIGHT/BOTTOM    // NEAR/LEFT & NEAR/LEFT/BOTTOM    if (            ((getProjectionType()     == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&            (that.getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR)))            ||            ((getProjectionType()     == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM)) &&            (that.getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR)))        )    {        if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) {            return true;        }    }     // NEAR/TOP & NEAR    if (            (getProjectionType()      == (PROJECTION_NEAR                   )) &&            (that.getProjectionType() == (PROJECTION_NEAR  | PROJECTION_TOP ))        )    {        if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) {            return true;        }    }     // NEAR/TOP & NEAR    if (            (that.getProjectionType() == (PROJECTION_NEAR                   )) &&            (getProjectionType()      == (PROJECTION_NEAR  | PROJECTION_TOP ))        )    {        if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) {            return true;        }    }     // NEAR/BOTTOM & NEAR    if (            (getProjectionType()      == (PROJECTION_NEAR                      )) &&            (that.getProjectionType() == (PROJECTION_NEAR  | PROJECTION_BOTTOM ))        )    {        if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) {            return true;        }    }     // NEAR/BOTTOM & NEAR    if (            (that.getProjectionType() == (PROJECTION_NEAR                      )) &&            (getProjectionType()      == (PROJECTION_NEAR  | PROJECTION_BOTTOM ))        )    {        if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) {            return true;        }    }     // NEAR/RIGHT & NEAR    if (            (getProjectionType()      == (PROJECTION_NEAR                      )) &&

Lines 1–500 of 1188.