// // VoxelProjectedPolygon.cpp - The projected shadow (on the 2D view plane) for a voxel // hifi // // Added by Brad Hefta-Gaub on 06/11/13. // #include #include "VoxelProjectedPolygon.h" #include "GeometryUtil.h" #include "Log.h" #include "SharedUtil.h" glm::vec2 BoundingBox::getVertex(int vertexNumber) const { switch (vertexNumber) { case BoundingBox::BOTTOM_LEFT: return corner; case BoundingBox::TOP_LEFT: return glm::vec2(corner.x, corner.y + size.y); case BoundingBox::BOTTOM_RIGHT: return glm::vec2(corner.x + size.x, corner.y); case BoundingBox::TOP_RIGHT: return corner + size; } assert(false); // not allowed return glm::vec2(0,0); } BoundingBox BoundingBox::topHalf() const { float halfY = size.y/2.0f; BoundingBox result(glm::vec2(corner.x,corner.y + halfY), glm::vec2(size.x, halfY)); return result; } BoundingBox BoundingBox::bottomHalf() const { float halfY = size.y/2.0f; BoundingBox result(corner, glm::vec2(size.x, halfY)); return result; } BoundingBox BoundingBox::leftHalf() const { float halfX = size.x/2.0f; BoundingBox result(corner, glm::vec2(halfX, size.y)); return result; } BoundingBox BoundingBox::rightHalf() const { float halfX = size.x/2.0f; BoundingBox result(glm::vec2(corner.x + halfX , corner.y), glm::vec2(halfX, size.y)); return result; } bool BoundingBox::contains(const BoundingBox& 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 BoundingBox::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 BoundingBox::explandToInclude(const BoundingBox& 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 BoundingBox::printDebugDetails(const char* label) const { if (label) { printLog(label); } else { printLog("BoundingBox"); } printLog("\n _set=%s\n corner=%f,%f size=%f,%f\n bounds=[(%f,%f) to (%f,%f)]\n", debug::valueOf(_set), corner.x, corner.y, size.x, size.y, corner.x, corner.y, corner.x+size.x, corner.y+size.y); } long VoxelProjectedPolygon::pointInside_calls = 0; long VoxelProjectedPolygon::occludes_calls = 0; long VoxelProjectedPolygon::intersects_calls = 0; VoxelProjectedPolygon::VoxelProjectedPolygon(const BoundingBox& 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 VoxelProjectedPolygon::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 VoxelProjectedPolygon::occludes(const VoxelProjectedPolygon& occludee, bool checkAllInView) const { VoxelProjectedPolygon::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 VoxelProjectedPolygon::occludes(const BoundingBox& boxOccludee) const { VoxelProjectedPolygon testee(boxOccludee); return occludes(testee); } bool VoxelProjectedPolygon::matches(const VoxelProjectedPolygon& 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 VoxelProjectedPolygon::matches(const BoundingBox& box) const { VoxelProjectedPolygon testee(box); return matches(testee); } bool VoxelProjectedPolygon::pointInside(const glm::vec2& point, bool* matchesVertex) const { VoxelProjectedPolygon::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; } /* // This old version of pointInside works on concave or convex polygons. But it's slower, and since we don't need // to support concave polygons, we don't need to do this extra heavy lifting bool VoxelProjectedPolygon::pointInside(const glm::vec2& point, bool* matchesVertex) const { // first check the bounding boxes, the point must be fully within the boounding box of this shadow if ((point.x > getMaxX()) || (point.y > getMaxY()) || (point.x < getMinX()) || (point.y < getMinY())) { return false; } //float e = (getMaxX() - getMinX()) / 100.0f; // some epsilon float e = 1.0f; // some epsilon // We need to have one ray that goes from a known outside position to the point in question. We'll pick a // start point outside of our min X, min Y glm::vec2 r1p1(getMinX() - e, point.y); glm::vec2 r1p2(point); glm::vec2 r2p1(getVertex(getVertexCount()-1)); // start with last vertex to first vertex glm::vec2 r2p2; // Test the ray against all sides int intersections = 0; bool someVertexMatches = false; for (int i = 0; i < getVertexCount(); i++) { r2p2 = getVertex(i); // if the point in question matches one of our vetices, then we consider it to NOT be inside. if (point.x == r2p2.x && point.y == r2p2.y) { // caller wants to know if we match any of the vertices if (matchesVertex) { *matchesVertex = true; } return false; } // if we're still processing, then check for intersections if (doLineSegmentsIntersect(r1p1, r1p2, r2p1, r2p2)) { intersections++; } r2p1 = r2p2; // set up for next side } // If odd number of intersections and we got here, we're inside return ((intersections & 1) == 1); } */ void VoxelProjectedPolygon::printDebugDetails() const { printf("VoxelProjectedPolygon..."); printf(" minX=%f maxX=%f minY=%f maxY=%f\n", getMinX(), getMaxX(), getMinY(), getMaxY()); printf(" vertex count=%d distance=%f\n", getVertexCount(), getDistance()); for (int i = 0; i < getVertexCount(); i++) { glm::vec2 point = getVertex(i); printf(" vertex[%d] = %f, %f \n", i, point.x, point.y); } } bool VoxelProjectedPolygon::intersects(const BoundingBox& box) const { VoxelProjectedPolygon testee(box); return intersects(testee); } bool VoxelProjectedPolygon::intersects(const VoxelProjectedPolygon& testee) const { VoxelProjectedPolygon::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 VoxelProjectedPolygon::intersectsOnAxes(const VoxelProjectedPolygon& 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 VoxelProjectedPolygon::canMerge(const VoxelProjectedPolygon& 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 )) && (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) ) { if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) { return true; } } // NEAR/RIGHT & NEAR if ( (that.getProjectionType() == (PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) ) { if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { return true; } } // NEAR/LEFT & NEAR if ( (getProjectionType() == (PROJECTION_NEAR )) && (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) ) { if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) { return true; } } // NEAR/LEFT & NEAR if ( (that.getProjectionType() == (PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) ) { if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { return true; } } // NEAR/RIGHT/TOP & NEAR/TOP if ( ((getProjectionType() == (PROJECTION_TOP | PROJECTION_NEAR )) && (that.getProjectionType() == (PROJECTION_TOP | PROJECTION_NEAR | PROJECTION_RIGHT ))) ) { if (getVertex(0) == that.getVertex(1) && getVertex(4) == that.getVertex(3)) { return true; } } // NEAR/RIGHT/TOP & NEAR/TOP if ( ((that.getProjectionType() == (PROJECTION_TOP | PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_TOP | PROJECTION_NEAR | PROJECTION_RIGHT ))) ) { if (getVertex(1) == that.getVertex(0) && getVertex(3) == that.getVertex(4)) { return true; } } // NEAR/RIGHT/BOTTOM & NEAR/BOTTOM if ( ((getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && (that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_RIGHT ))) ) { if (getVertex(1) == that.getVertex(2) && getVertex(5) == that.getVertex(4)) { return true; } } // NEAR/RIGHT/BOTTOM & NEAR/BOTTOM if ( ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_RIGHT ))) ) { if (getVertex(2) == that.getVertex(1) && getVertex(4) == that.getVertex(5)) { return true; } } // NEAR/LEFT/BOTTOM & NEAR/BOTTOM if ( ((getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && (that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT ))) ) { if (getVertex(2) == that.getVertex(0) && getVertex(4) == that.getVertex(4)) { return true; } } // NEAR/LEFT/BOTTOM & NEAR/BOTTOM if ( ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT ))) ) { if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) { return true; } } // RIGHT/NEAR/BOTTOM // RIGHT/NEAR/TOP // LEFT/NEAR/BOTTOM // LEFT/NEAR/TOP if ( (getProjectionType() == that.getProjectionType()) && ( getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) || getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) || getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM ) || getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP ) ) ) { if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) { return true; } if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) { return true; } if (getVertex(2) == that.getVertex(1) && getVertex(4) == that.getVertex(5)) { return true; } if (getVertex(1) == that.getVertex(2) && getVertex(5) == that.getVertex(4)) { return true; } if (getVertex(1) == that.getVertex(0) && getVertex(3) == that.getVertex(4)) { return true; } if (getVertex(0) == that.getVertex(1) && getVertex(4) == that.getVertex(3)) { return true; } } return false; } void VoxelProjectedPolygon::merge(const VoxelProjectedPolygon& that) { // 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)) { //setVertex(0, this.getVertex(0)); // no change setVertex(1, that.getVertex(1)); setVertex(2, that.getVertex(2)); setVertex(3, that.getVertex(3)); setVertex(4, that.getVertex(4)); //setVertex(5, this.getVertex(5)); // no change return; // done } if (getVertex(0) == that.getVertex(1) && getVertex(5) == that.getVertex(4)) { setVertex(0, that.getVertex(0)); //setVertex(1, this.getVertex(1)); // no change //setVertex(2, this.getVertex(2)); // no change //setVertex(3, this.getVertex(3)); // no change //setVertex(4, that.getVertex(4)); // no change setVertex(5, that.getVertex(5)); return; // done } if (getVertex(2) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, this.getVertex(1)); // no change setVertex(2, that.getVertex(2)); setVertex(3, that.getVertex(3)); //setVertex(4, this.getVertex(4)); // no change //setVertex(5, that.getVertex(5)); // no change return; // done } if (getVertex(1) == that.getVertex(2) && getVertex(4) == that.getVertex(3)) { setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); //setVertex(2, this.getVertex(2)); // no change //setVertex(3, that.getVertex(3)); // no change setVertex(4, that.getVertex(4)); setVertex(5, that.getVertex(5)); return; // done } } // NEAR/BOTTOM if ( (getProjectionType() == that.getProjectionType()) && ( getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM) ) ) { if (getVertex(0) == that.getVertex(5) && getVertex(3) == that.getVertex(4)) { setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); setVertex(2, that.getVertex(2)); setVertex(3, that.getVertex(3)); //setVertex(4, this.getVertex(4)); // no change //setVertex(5, that.getVertex(5)); // no change return; // done } if (getVertex(5) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, that.getVertex(1)); // no change //setVertex(2, this.getVertex(2)); // no change //setVertex(3, that.getVertex(3)); // no change setVertex(4, that.getVertex(4)); setVertex(5, that.getVertex(5)); return; // done } if (getVertex(1) == that.getVertex(0) && getVertex(2) == that.getVertex(3)) { //setVertex(0, this.getVertex(0)); // no change setVertex(1, that.getVertex(1)); setVertex(2, that.getVertex(2)); //setVertex(3, that.getVertex(3)); // no change //setVertex(4, this.getVertex(4)); // no change //setVertex(5, that.getVertex(5)); // no change return; // done } if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(2)) { setVertex(0, that.getVertex(0)); //setVertex(1, this.getVertex(1)); // no change //setVertex(2, that.getVertex(2)); // no change setVertex(3, that.getVertex(3)); setVertex(4, that.getVertex(4)); setVertex(5, that.getVertex(5)); return; // done } } // NEAR/TOP if ( (getProjectionType() == that.getProjectionType()) && ( getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP) ) ) { if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); //setVertex(2, this.getVertex(2)); // no change //setVertex(3, that.getVertex(3)); // no change //setVertex(4, this.getVertex(4)); // no change //setVertex(5, that.getVertex(5)); // no change return; // done } if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, that.getVertex(1)); // no change setVertex(2, that.getVertex(2)); setVertex(3, that.getVertex(3)); setVertex(4, that.getVertex(4)); setVertex(5, that.getVertex(5)); return; // done } if (getVertex(4) == that.getVertex(5) && getVertex(3) == that.getVertex(2)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, that.getVertex(1)); // no change //setVertex(2, that.getVertex(2)); // no change setVertex(3, that.getVertex(3)); setVertex(4, that.getVertex(4)); //setVertex(5, that.getVertex(5)); // no change return; // done } if (getVertex(5) == that.getVertex(4) && getVertex(2) == that.getVertex(3)) { setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); setVertex(2, that.getVertex(2)); //setVertex(3, this.getVertex(3)); // no change //setVertex(4, that.getVertex(3)); // no change setVertex(5, that.getVertex(5)); return; // done } } // 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)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, this.getVertex(1)); // no change //setVertex(2, this.getVertex(2)); // no change setVertex(3, that.getVertex(3)); setVertex(4, that.getVertex(4)); setVertex(5, that.getVertex(5)); setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR)); return; // done } } // 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)) { setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); setVertex(2, that.getVertex(2)); //setVertex(3, this.getVertex(3)); // no change //setVertex(4, this.getVertex(4)); // no change //setVertex(5, this.getVertex(5)); // no change //setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR)); // no change return; // done } } // 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)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, this.getVertex(1)); // no change //setVertex(2, this.getVertex(2)); // no change setVertex(3, that.getVertex(3)); setVertex(4, that.getVertex(4)); setVertex(5, that.getVertex(5)); //setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR)); // no change return; // done } } // 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)) { setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); setVertex(2, that.getVertex(2)); //setVertex(3, this.getVertex(3)); // no change //setVertex(4, this.getVertex(4)); // no change //setVertex(5, this.getVertex(5)); // no change setProjectionType((PROJECTION_RIGHT | PROJECTION_NEAR)); return; // done } } // NEAR/TOP & NEAR if ( (getProjectionType() == (PROJECTION_NEAR )) && (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) ) { if (getVertex(0) == that.getVertex(5) && getVertex(1) == that.getVertex(2)) { setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); //setVertex(2, this.getVertex(2)); // no change //setVertex(3, this.getVertex(3)); // no change //setVertexCount(4); // no change //setProjectionType((PROJECTION_NEAR)); // no change return; // done } } // NEAR/TOP & NEAR if ( (that.getProjectionType() == (PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_NEAR | PROJECTION_TOP )) ) { if (getVertex(5) == that.getVertex(0) && getVertex(2) == that.getVertex(1)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, this.getVertex(1)); // no change setVertex(2, that.getVertex(2)); setVertex(3, that.getVertex(3)); setVertexCount(4); setProjectionType((PROJECTION_NEAR)); return; // done } } // NEAR/BOTTOM & NEAR if ( (getProjectionType() == (PROJECTION_NEAR )) && (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) ) { if (getVertex(2) == that.getVertex(3) && getVertex(3) == that.getVertex(0)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, this.getVertex(1)); // no change setVertex(2, that.getVertex(4)); setVertex(3, that.getVertex(5)); //setVertexCount(4); // no change //setProjectionType((PROJECTION_NEAR)); // no change } } // NEAR/BOTTOM & NEAR if ( (that.getProjectionType() == (PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_NEAR | PROJECTION_BOTTOM )) ) { if (getVertex(3) == that.getVertex(2) && getVertex(0) == that.getVertex(3)) { setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); setVertex(2, getVertex(4)); setVertex(3, getVertex(5)); setVertexCount(4); setProjectionType((PROJECTION_NEAR)); return; // done } } // NEAR/RIGHT & NEAR if ( (getProjectionType() == (PROJECTION_NEAR )) && (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) ) { if (getVertex(0) == that.getVertex(1) && getVertex(3) == that.getVertex(4)) { setVertex(0, that.getVertex(0)); //setVertex(1, this.getVertex(1)); // no change //setVertex(2, this.getVertex(2)); // no change setVertex(3, that.getVertex(5)); //setVertexCount(4); // no change //setProjectionType((PROJECTION_NEAR)); // no change } } // NEAR/RIGHT & NEAR if ( (that.getProjectionType() == (PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_NEAR | PROJECTION_RIGHT )) ) { if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { //setVertex(0, this.getVertex(0)); // no change setVertex(1, that.getVertex(1)); setVertex(2, that.getVertex(2)); setVertex(3, getVertex(5)); setVertexCount(4); setProjectionType((PROJECTION_NEAR)); return; // done } } // NEAR/LEFT & NEAR if ( (getProjectionType() == (PROJECTION_NEAR )) && (that.getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) ) { if (getVertex(1) == that.getVertex(1) && getVertex(2) == that.getVertex(4)) { //setVertex(0, this.getVertex()); // no change setVertex(1, that.getVertex(2)); setVertex(2, that.getVertex(3)); //setVertex(3, this.getVertex(3)); // no change //setVertexCount(4); // no change //setProjectionType((PROJECTION_NEAR)); // no change return; // done } } // NEAR/LEFT & NEAR if ( (that.getProjectionType() == (PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_NEAR | PROJECTION_LEFT )) ) { if (getVertex(1) == that.getVertex(0) && getVertex(4) == that.getVertex(3)) { setVertex(0, that.getVertex(0)); setVertex(1, getVertex(2)); setVertex(2, getVertex(3)); setVertex(3, that.getVertex(3)); setVertexCount(4); setProjectionType((PROJECTION_NEAR)); return; // done } } // NEAR/RIGHT/TOP & NEAR/TOP if ( ((getProjectionType() == (PROJECTION_TOP | PROJECTION_NEAR )) && (that.getProjectionType() == (PROJECTION_TOP | PROJECTION_NEAR | PROJECTION_RIGHT ))) ) { if (getVertex(0) == that.getVertex(1) && getVertex(4) == that.getVertex(3)) { setVertex(0, that.getVertex(0)); //setVertex(1, this.getVertex(1)); // no change //setVertex(2, this.getVertex(2)); // no change //setVertex(3, this.getVertex(3)); // no change setVertex(4, that.getVertex(4)); setVertex(5, that.getVertex(5)); return; // done } } // NEAR/RIGHT/TOP & NEAR/TOP if ( ((that.getProjectionType() == (PROJECTION_TOP | PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_TOP | PROJECTION_NEAR | PROJECTION_RIGHT ))) ) { if (getVertex(1) == that.getVertex(0) && getVertex(3) == that.getVertex(4)) { //setVertex(0, this.getVertex(0)); // no change setVertex(1, that.getVertex(1)); setVertex(2, that.getVertex(2)); setVertex(3, that.getVertex(3)); //setVertex(4, this.getVertex(4)); // no change //setVertex(5, this.getVertex(5)); // no change setProjectionType((PROJECTION_TOP | PROJECTION_NEAR)); return; // done } } // NEAR/RIGHT/BOTTOM & NEAR/BOTTOM if ( ((getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && (that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_RIGHT ))) ) { if (getVertex(1) == that.getVertex(2) && getVertex(5) == that.getVertex(4)) { setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); //setVertex(2, this.getVertex(2)); // no change //setVertex(3, this.getVertex(3)); // no change //setVertex(4, this.getVertex(4)); // no change setVertex(5, that.getVertex(5)); return; // done } } // NEAR/RIGHT/BOTTOM & NEAR/BOTTOM if ( ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_RIGHT ))) ) { if (getVertex(2) == that.getVertex(1) && getVertex(4) == that.getVertex(5)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, this.getVertex(1)); // no change setVertex(2, that.getVertex(2)); setVertex(3, that.getVertex(3)); setVertex(4, that.getVertex(4)); //setVertex(5, this.getVertex(5)); // no change setProjectionType((PROJECTION_BOTTOM | PROJECTION_NEAR)); return; // done } } // NEAR/LEFT/BOTTOM & NEAR/BOTTOM if ( ((getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && (that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT ))) ) { if (getVertex(2) == that.getVertex(0) && getVertex(4) == that.getVertex(4)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, this.getVertex(1)); // no change setVertex(2, that.getVertex(1)); setVertex(3, that.getVertex(2)); setVertex(4, that.getVertex(3)); //setVertex(5, this.getVertex(5)); // no change return; // done } } // NEAR/LEFT/BOTTOM & NEAR/BOTTOM if ( ((that.getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR )) && (getProjectionType() == (PROJECTION_BOTTOM | PROJECTION_NEAR | PROJECTION_LEFT ))) ) { if (getVertex(0) == that.getVertex(2) && getVertex(4) == that.getVertex(4)) { // we need to do this in an unusual order, because otherwise we'd overwrite our own values setVertex(4, getVertex(3)); setVertex(3, getVertex(2)); setVertex(2, getVertex(1)); setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); setVertex(5, that.getVertex(5)); setProjectionType((PROJECTION_BOTTOM | PROJECTION_NEAR)); return; // done } } // RIGHT/NEAR/BOTTOM // RIGHT/NEAR/TOP // LEFT/NEAR/BOTTOM // LEFT/NEAR/TOP if ( (getProjectionType() == that.getProjectionType()) && ( getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_BOTTOM ) || getProjectionType() == (PROJECTION_RIGHT | PROJECTION_NEAR | PROJECTION_TOP ) || getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_BOTTOM ) || getProjectionType() == (PROJECTION_LEFT | PROJECTION_NEAR | PROJECTION_TOP ) ) ) { if (getVertex(0) == that.getVertex(5) && getVertex(2) == that.getVertex(3)) { setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); setVertex(2, that.getVertex(2)); //setVertex(3, this.getVertex(3)); // no change //setVertex(4, this.getVertex(4)); // no change //setVertex(5, this.getVertex(5)); // no change return; // done } if (getVertex(5) == that.getVertex(0) && getVertex(3) == that.getVertex(2)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, this.getVertex(1)); // no change //setVertex(2, this.getVertex(2)); // no change setVertex(3, that.getVertex(3)); setVertex(4, that.getVertex(4)); setVertex(5, that.getVertex(5)); return; // done } if (getVertex(2) == that.getVertex(1) && getVertex(4) == that.getVertex(5)) { //setVertex(0, this.getVertex(0)); // no change //setVertex(1, this.getVertex(1)); // no change setVertex(2, that.getVertex(2)); setVertex(3, that.getVertex(3)); setVertex(4, that.getVertex(4)); //setVertex(5, this.getVertex(5)); // no change return; // done } if (getVertex(1) == that.getVertex(2) && getVertex(5) == that.getVertex(4)) { setVertex(0, that.getVertex(0)); setVertex(1, that.getVertex(1)); //setVertex(2, this.getVertex(2)); // no change //setVertex(3, this.getVertex(3)); // no change //setVertex(4, this.getVertex(4)); // no change setVertex(5, that.getVertex(5)); return; // done } // if this.([1],[3]) == that.([0],[4]) then create polygon: this.[0], that.[1], that.[2], that.[3], this.[4], this.[5] if (getVertex(1) == that.getVertex(0) && getVertex(3) == that.getVertex(4)) { //setVertex(0, this.getVertex(0)); // no change setVertex(1, that.getVertex(1)); setVertex(2, that.getVertex(2)); setVertex(3, that.getVertex(3)); //setVertex(4, this.getVertex(4)); // no change //setVertex(5, this.getVertex(5)); // no change return; // done } // if this.([0],[4]) == that.([1],[3]) then create polygon: that.[0], this.[1], this.[2], this.[3], that.[4], that.[5] if (getVertex(0) == that.getVertex(1) && getVertex(4) == that.getVertex(3)) { setVertex(0, that.getVertex(0)); //setVertex(1, this.getVertex(1)); // no change //setVertex(2, this.getVertex(2)); // no change //setVertex(3, this.getVertex(3)); // no change setVertex(4, that.getVertex(4)); setVertex(5, that.getVertex(5)); return; // done } } }