int edgesIntersect(double x1, double x2, double y1, double y2, LRect r) { int result = 0; if (linesIntersect(x1, x2, r.x1, r.x2, y1, y2, r.y1, r.y2) || linesIntersect(x1, x2, r.x2, r.x3, y1, y2, r.y2, r.y3) || linesIntersect(x1, x2, r.x3, r.x4, y1, y2, r.y3, r.y4) || linesIntersect(x1, x2, r.x4, r.x1, y1, y2, r.y4, r.y1)) result = 1; return result; }
bool Drawable::shapeOverlaps(const std::vector<Vector2>& edges) const { uint8_t inCorners = 0; for (const Vector2& corner : edges) { if (corner.x >= boundingBox.min.x && corner.x <= boundingBox.max.x && corner.y >= boundingBox.min.y && corner.y <= boundingBox.max.y) { return true; } if (corner.x < boundingBox.min.x && corner.y < boundingBox.min.y) inCorners |= 0x01; if (corner.x > boundingBox.max.x && corner.y < boundingBox.min.y) inCorners |= 0x02; if (corner.x > boundingBox.max.x && corner.y > boundingBox.max.y) inCorners |= 0x04; if (corner.x < boundingBox.min.x && corner.y > boundingBox.max.y) inCorners |= 0x08; } // bounding box is bigger than rectangle if (inCorners == 0x0F) { return true; } Vector2 boundingBoxCorners[4] = { Vector2(boundingBox.min), Vector2(boundingBox.max.x, boundingBox.min.y), Vector2(boundingBox.max), Vector2(boundingBox.min.x, boundingBox.max.y) }; for (uint32_t current = 0; current < edges.size(); ++current) { uint32_t next = (current == (edges.size() -1)) ? 0 : current + 1; if (linesIntersect(Vector2(edges[current].x, edges[current].y), Vector2(edges[next].x, edges[next].y), boundingBoxCorners[0], boundingBoxCorners[1]) || // left linesIntersect(Vector2(edges[current].x, edges[current].y), Vector2(edges[next].x, edges[next].y), boundingBoxCorners[1], boundingBoxCorners[2]) || // top linesIntersect(Vector2(edges[current].x, edges[current].y), Vector2(edges[next].x, edges[next].y), boundingBoxCorners[2], boundingBoxCorners[3]) || // right linesIntersect(Vector2(edges[current].x, edges[current].y), Vector2(edges[next].x, edges[next].y), boundingBoxCorners[3], boundingBoxCorners[0])) // bottom { return true; } } return false; }
bool isPathSelfIntersecting(const vector<CubicSpline> &splines) { if(splines.size() == 0) { return false; } const int pointsPerSpline = 20; vector<VectorF> points; points.reserve(1 + pointsPerSpline * splines.size()); points.push_back(splines[0].evaluate(0)); for(size_t i = 0; i < splines.size(); i++) { for(int j = 1; j <= pointsPerSpline; j++) { points.push_back(splines[i].evaluate((float)j / pointsPerSpline)); } } for(size_t i = 2; i < points.size(); i++) { for(size_t j = 1; j < i; j++) { if(linesIntersect(points[i - 1], points[i], points[j - 1], points[j], eps)) { return true; } } } return false; }
bool SnakeLayer::testDie() { LineNode* n = static_cast<LineNode*>(*lineGroup->getChildren().rbegin()); Point end = n->getEnd(); if (!bounds.containsPoint(end)) { gameOver(); return true; } for (int i = 0; i < lineGroup->getChildrenCount(); i++) { LineNode* li = static_cast<LineNode*>(*(lineGroup->getChildren().begin() + i)); for (int j = 0; j < lineGroup->getChildrenCount(); j++) { if (abs((int) i - (int) j) <= 1) continue; LineNode* lj = static_cast<LineNode*>(*(lineGroup->getChildren().begin() + j)); if (linesIntersect( li->getStart(), li->getEnd(), lj->getStart(), lj->getEnd())) { gameOver(); return true; } } } return false; }
bool CubicSpline::isSelfIntersecting() const { const int pointsPerSpline = 20; vector<VectorF> points; points.reserve(1 + pointsPerSpline); for(int i = 0; i <= pointsPerSpline; i++) { points.push_back(evaluate((float)i / pointsPerSpline)); } for(size_t i = 2; i < points.size(); i++) { for(size_t j = 1; j < i; j++) { if(linesIntersect(points[i - 1], points[i], points[j - 1], points[j], (abs(i - j) > 1 ? 0 : eps))) { return true; } } } return false; }
bool CubicSpline::intersects(const CubicSpline &rt, VectorF ignoreAxis) const { #if 1 vector<VectorF> path1 = getSplinePoints(*this); vector<VectorF> path2 = getSplinePoints(rt); for(size_t i = 1; i < path1.size(); i++) { for(size_t j = 1; j < path2.size(); j++) { if(linesIntersect(path1[i - 1], path1[i], path2[j - 1], path2[j], 0)) return true; } } return false; #else const int splitCount = 50; // number of line segments to split spline into ignoreAxis = normalize(ignoreAxis); for(int segmentNumber = 0; segmentNumber < splitCount; segmentNumber++) { float startT = (float)(segmentNumber) / splitCount; float endT = (float)(segmentNumber + 1) / splitCount; VectorF startP = rt.evaluate(startT); startP -= ignoreAxis * dot(ignoreAxis, startP); // move to plane normal to ignoreAxis VectorF endP = rt.evaluate(endT); endP -= ignoreAxis * dot(ignoreAxis, endP); // move to plane normal to ignoreAxis VectorF delta = endP - startP; if(absSquared(delta) < eps * eps) // if delta is too small { continue; } // solve dot(evaluate(t), cross(ignoreAxis, delta)) == 0 and it intersects if dot(evaluate(t) - startP, delta) / dot(delta, delta) is in [0, 1] and t is in [0, 1] VectorF normal = cross(ignoreAxis, delta); float cubic = dot(getCubic(), normal); float quadratic = dot(getQuadratic(), normal); float linear = dot(getLinear(), normal); float constant = dot(getConstant(), normal); float intersections[3]; int intersectionCount = solveCubic(constant, linear, quadratic, cubic, intersections); for(int i = 0; i < intersectionCount; i++) { float t = intersections[i]; if(t < 0 || t > 1) { continue; } float v = dot(evaluate(t) - startP, delta) / dot(delta, delta); if(v < 0 || v > 1) { continue; } return true; } } return false; #endif }
Map::CollisionSide Map::findCollisionSide(GameEntity* entity1, GameEntity* entity2) { RectangleD frame1 = entity1->getCollisionFrame(); RectangleD frame2 = entity2->getCollisionFrame(); RectangleD intersect = frame1.getIntersect(frame2); if(intersect.width==0 || intersect.height==0) { //no collision happening return COLLISION_NONE; } Vector2d pos1End = entity1->getPosition(); Vector2d pos1Begin(entity1->getPreviousX(), entity1->getPreviousY()); Vector2d pos1Dif(pos1End.x-pos1Begin.x, pos1End.y-pos1Begin.y); Vector2d pos2End = entity2->getPosition(); Vector2d pos2Begin(entity2->getPreviousX(), entity2->getPreviousY()); pos2Begin += pos1Dif; Vector2d pos2Dif(pos2End.x-pos2Begin.x, pos2End.y-pos2Begin.y); double frame1_right = frame1.x + frame1.width; double frame1_bottom = frame1.y + frame1.height; RectangleD prevFrame2 = frame2; prevFrame2.x -= pos2Dif.x; prevFrame2.y -= pos2Dif.y; double prevFrame2_right = prevFrame2.x+prevFrame2.width; double prevFrame2_bottom = prevFrame2.y+prevFrame2.height; double dfix = 0.0000001; if(prevFrame2_bottom <= (frame1.y+dfix)) //above frame1 { if(prevFrame2_right <= (frame1.x+dfix)) //top left { Vector2d lineBL_p1(prevFrame2.x, prevFrame2_bottom); Vector2d lineBL_p2(lineBL_p1.x+pos2Dif.x, lineBL_p1.y+pos2Dif.y); Vector2d lineBR_p1(prevFrame2_right, prevFrame2_bottom); Vector2d lineBR_p2(lineBR_p1.x+pos2Dif.x, lineBR_p1.y+pos2Dif.y); Vector2d lineTR_p1(prevFrame2_right, prevFrame2.y); Vector2d lineTR_p2(lineTR_p1.x+pos2Dif.x, lineTR_p1.y+pos2Dif.y); Vector2d box_TR(frame1_right, frame1.y); Vector2d box_TL(frame1.x, frame1.y); Vector2d box_BL(frame1.x, frame1_bottom); bool lineBR_top = linesIntersect(lineBR_p1, lineBR_p2, box_TL, box_TR); if(lineBR_top) { //push up return COLLISION_TOP; } bool lineBR_left = linesIntersect(lineBR_p1, lineBR_p2, box_TL, box_BL); if(lineBR_left) { //push left return COLLISION_LEFT; } PolygonD polyRight; polyRight.addPoint(lineTR_p1); polyRight.addPoint(lineTR_p2); polyRight.addPoint(lineBR_p2); polyRight.addPoint(lineBR_p1); if(polyRight.contains(box_BL)) { //push left return COLLISION_LEFT; } //push up return COLLISION_TOP; } else if((prevFrame2.x+dfix) >= frame1_right) //top right { Vector2d lineBR_p1(prevFrame2_right, prevFrame2_bottom); Vector2d lineBR_p2(lineBR_p1.x+pos2Dif.x, lineBR_p1.y+pos2Dif.y); Vector2d lineBL_p1(prevFrame2.x, prevFrame2_bottom); Vector2d lineBL_p2(lineBL_p1.x+pos2Dif.x, lineBL_p1.y+pos2Dif.y); Vector2d lineTL_p1(prevFrame2.x, prevFrame2.y); Vector2d lineTL_p2(lineTL_p1.x+pos2Dif.x, lineTL_p1.y+pos2Dif.y); Vector2d box_TL(frame1.x, frame1.y); Vector2d box_TR(frame1_right, frame1.y); Vector2d box_BR(frame1_right, frame1_bottom); bool lineBL_top = linesIntersect(lineBL_p1, lineBL_p2, box_TL, box_TR); if(lineBL_top) { //push up return COLLISION_TOP; } bool lineBL_right = linesIntersect(lineBL_p1, lineBL_p2, box_TR, box_BR); if(lineBL_right) { //push right return COLLISION_RIGHT; } PolygonD polyLeft; polyLeft.addPoint(lineTL_p1); polyLeft.addPoint(lineTL_p2); polyLeft.addPoint(lineBL_p2); polyLeft.addPoint(lineBL_p1); if(polyLeft.contains(box_BR)) { //push right return COLLISION_RIGHT; } //push up return COLLISION_TOP; } else //top middle { //push up return COLLISION_TOP; } } else if((prevFrame2.y+dfix) >= frame1_bottom) //below frame1 { if(prevFrame2_right <= (frame1.x+dfix)) //bottom left { Vector2d lineBR_p1(prevFrame2_right, prevFrame2_bottom); Vector2d lineBR_p2(lineBR_p1.x+pos2Dif.x, lineBR_p1.y+pos2Dif.y); Vector2d lineTR_p1(prevFrame2_right, prevFrame2.y); Vector2d lineTR_p2(lineTR_p1.x+pos2Dif.x, lineTR_p1.y+pos2Dif.y); Vector2d lineTL_p1(prevFrame2.x, prevFrame2.y); Vector2d lineTL_p2(lineTL_p1.x+pos2Dif.x, lineTL_p1.y+pos2Dif.y); Vector2d box_TL(frame1.x, frame1.y); Vector2d box_BL(frame1.x, frame1_bottom); Vector2d box_BR(frame1_right, frame1_bottom); bool lineTR_top = linesIntersect(lineTR_p1, lineTR_p2, box_BL, box_BR); if(lineTR_top) { //push down return COLLISION_BOTTOM; } bool lineTR_left = linesIntersect(lineTR_p1, lineTR_p2, box_TL, box_BL); if(lineTR_left) { //push left return COLLISION_LEFT; } PolygonD polyRight; polyRight.addPoint(lineTR_p1); polyRight.addPoint(lineTR_p2); polyRight.addPoint(lineBR_p2); polyRight.addPoint(lineBR_p1); if(polyRight.contains(box_TL)) { //push left return COLLISION_LEFT; } //push down return COLLISION_BOTTOM; } else if((prevFrame2.x+dfix) >= frame1_right) //bottom right { Vector2d lineBL_p1(prevFrame2.x, prevFrame2_bottom); Vector2d lineBL_p2(lineBL_p1.x+pos2Dif.x, lineBL_p1.y+pos2Dif.y); Vector2d lineTL_p1(prevFrame2.x, prevFrame2.y); Vector2d lineTL_p2(lineTL_p1.x+pos2Dif.x, lineTL_p1.y+pos2Dif.y); Vector2d lineTR_p1(prevFrame2_right, prevFrame2.y); Vector2d lineTR_p2(lineTR_p1.x+pos2Dif.x, lineTR_p1.y+pos2Dif.y); Vector2d box_TR(frame1_right, frame1.y); Vector2d box_BR(frame1_right, frame1_bottom); Vector2d box_BL(frame1.x, frame1_bottom); bool lineTL_top = linesIntersect(lineTL_p1, lineTL_p2, box_BL, box_BR); if(lineTL_top) { //push down return COLLISION_BOTTOM; } bool lineTL_right = linesIntersect(lineTL_p1, lineTL_p2, box_TR, box_BR); if(lineTL_right) { //push right return COLLISION_RIGHT; } PolygonD polyLeft; polyLeft.addPoint(lineTL_p1); polyLeft.addPoint(lineTL_p2); polyLeft.addPoint(lineBL_p2); polyLeft.addPoint(lineBL_p1); if(polyLeft.contains(box_TR)) { //push right return COLLISION_RIGHT; } //push down return COLLISION_BOTTOM; } else //bottom middle { //push down return COLLISION_BOTTOM; } } else //within top and bottom of frame 1 { if(prevFrame2_right <= (frame1.x+dfix)) //middle left { //push left return COLLISION_LEFT; } else if((prevFrame2.x+dfix) >= frame1_right) //middle right { //push right return COLLISION_RIGHT; } else { //this case should never happen unless some dingus updates without checking collisions, //or because double precision is a bitch sometimes Console::writeErrorLine("findCollisionSide hit an impossible case"); return COLLISION_NONE; } } }
/* *--------------------------------------------------------- * This routine will return the edge index * through which the cell was pushed across. * The variable 'direction' will be TRUE if * the edge was found from vstart->vend and FALSE if * the edge is found from vend->vstart *--------------------------------------------------------- */ int cellInPolyAndEdge( CELL *c, int *direction, Point3D *intersec3D, double *t, int prevEdge ) { int nverts, whichFace; int i, whichEdge, we[3], dir[3], it[3]; Point2D p, v, qCurrent, qPrevious, intersec[3]; Point2D v0, v1; Point3D p0, p1; double z[3], tt[3]; whichFace = c->whichFace; nverts = faces[whichFace].nverts; /* * Implementation dependent code! Assumes that we are * always working with triangles! */ if ( nverts != 3 ) errorMsg("Don't know how to deal with non-triangular faces (relax.c)!"); /* * Map the current and previous cell's position to the * 2D space of the face. I want to compute * the intersection between a line defined by the * previous and current cell's position and the edge */ mapOntoPolySpace(whichFace, c->x, c->y, c->z, &qCurrent ); mapOntoPolySpace(whichFace, c->xp, c->yp, c->zp, &qPrevious ); #ifdef VERBOSE fprintf( stderr, "qPrevious [X] = %f [Y] = %f\n", qPrevious.x, qPrevious.y ); fprintf( stderr, "qCurrent [X] = %f [Y] = %f\n", qCurrent.x, qCurrent.y ); #endif for(i = 0; i < nverts; i++) { we[i] = -1; tt[i] = -1; it[i] = -1; dir[i] = -1; p0.x = vert[faces[whichFace].v[i]].pos.x; p0.y = vert[faces[whichFace].v[i]].pos.y; p0.z = vert[faces[whichFace].v[i]].pos.z; p1.x = vert[faces[whichFace].v[(i+1)%nverts]].pos.x; p1.y = vert[faces[whichFace].v[(i+1)%nverts]].pos.y; p1.z = vert[faces[whichFace].v[(i+1)%nverts]].pos.z; mapOntoPolySpace(whichFace, p0.x, p0.y, p0.z, &v0); mapOntoPolySpace(whichFace, p1.x, p1.y, p1.z, &v1); #ifdef VERBOSE fprintf( stderr, "[X0] = %f [Y0] = %f [Z0] = %f\n", p0.x, p0.y, p0.z ); fprintf( stderr, "[X1] = %f [Y1] = %f [Z1] = %f\n", p1.x, p1.y, p1.z ); fprintf( stderr, "v0 [X] = %f [Y] = %f\n", v0.x, v0.y ); fprintf( stderr, "v1 [X] = %f [Y] = %f\n", v1.x, v1.y ); #endif p.x = qCurrent.x - v0.x; p.y = qCurrent.y - v0.y; v.x = v1.x - v0.x; v.y = v1.y - v0.y; z[i] = v.x * p.y - p.x * v.y; if ( Negative(z[i]) ) { /* find which edge is this */ we[i] = findEdgeForVert( faces[whichFace].v[i], faces[whichFace].v[(i+1)%nverts], &(dir[i]) ); /* * The difference between 'linesIntersect' and 'goodLinesIntersect' is that * 'goodLinesIntersect' does not do a bounding box test, whereas 'linesIntersect' * does. I have the 2 versions since I thought that sometimes, due to * rounding off, the bounding box test was giving me wrong results. */ /*it[i] = goodLinesIntersect( qPrevious, qCurrent, v0, v1, &(intersec[i]), &(tt[i]) );*/ it[i] = linesIntersect( qPrevious, qCurrent, v0, v1, &(intersec[i]), &(tt[i]) ); } } /* * If all z are greater or equal to 0.0, then the cell * is inside the polygon. Otherwise we proceed to * find out which edge it crossed */ /*if ( z[0] >= 0.0 && z[1] >= 0.0 && z[2] >= 0.0 ) return -1;*/ if ( GreaterEqualZero(z[0]) && GreaterEqualZero(z[1]) && GreaterEqualZero(z[2]) ) return -1; else{ #ifdef VERBOSE /*fprintf( stderr, "qCurrent [X] = %f [Y] = %f\n", qCurrent.x, qCurrent.y ); fprintf( stderr, "qPrevious [X] = %f [Y] = %f\n", qPrevious.x, qPrevious.y ); fprintf( stderr, "\nGeometry vertices for face %d\n", whichFace );*/ fprintf( stderr, "\nCell NOT inside polygon!\n"); #endif for(i = 0; i < nverts; i++) { if ( Negative( z[i] ) /*z[i] < 0.0*/ && it[i] == DO_INTERSECT ) { #ifdef VERBOSE fprintf( stderr, "intersec [X] = %f [Y] = %f\n", intersec[i].x, intersec[i].y ); fprintf( stderr, "[%d] z = %f e = %d dir = %d\n", i, z[i], we[i], dir[i] ); fprintf( stderr, "intersect = %d t = %lg\n", it[i], tt[i]); #endif /* * I have to make sure here that the just found intersection * is not the same one as before */ if ( prevEdge != we[i] ){ mapFromPolySpace(whichFace, intersec[i].x, intersec[i].y, intersec3D ); *t = tt[i]; *direction = dir[i]; #ifdef VERBOSE fprintf( stderr, "2D: x = %f y = %f\n", intersec[i].x, intersec[i].y); fprintf( stderr, "3D: x = %f y = %f z = %f\n", intersec3D->x, intersec3D->y, intersec3D->z ); #endif return we[i]; } } } /* * If I have reached this point we have a problem. * Before leaving the program I am printing which * should be useful info */ for(i = 0; i < nverts; i++) { //fprintf( stderr, "[%d] z = %lg t = %lg intersec = %d e = %d dir = %d\n", // i, z[i], tt[i], it[i], we[i],dir[i] ); if ( we[i] != -1 ){ //fprintf( stderr, "edge = %d pf = %d nf = %d cell = %d\n", // we[i], edges[we[i]].pf, edges[we[i]].nf, c->ctype ); /*fprintf( stderr, "matrix for next->previous face:\n"); printMatrix( edges[we[i]].np ); fprintf( stderr, "matrix for previous->next face:\n"); printMatrix( edges[we[i]].pn );*/ } } //fprintf( stderr, "For face %d we have the neighboring faces:\n", whichFace ); for(i = 0; i < faces[whichFace].nPrimFaces; i++) { //fprintf( stderr, "[%d] angle = %f\n", // faces[whichFace].primFaces[i], // rad2deg(faces[whichFace].rotAngles[i]) ); } return -2; //errorMsg("If I reached this point I could not find an edge to move cells!"); } }