///@brief 点到线段最近一个点 ///@param[in] p0--要判断点, s0,s1--线段两个端点 ///@return crosspoint---最近的点 ///@author DionysosLai,[email protected] ///@retval ///@post ///@version 1.0 ///@data 2014-7-28 16:58 cocos2d::CCPoint nearestPointToSegmentLine( const cocos2d::CCPoint& p0, const cocos2d::CCPoint& s0, const cocos2d::CCPoint& s1 ) { /// 判断线段是否是一个点 if (s0.equals(s1)) { return s0; } /// 初始垂足为0; CCPoint crossPoint = CCPointZero; do { /// 判断线段是否平行于x轴 if (s0.y == s1.y) { crossPoint = ccp(p0.x, s0.y); break; } /// 判断线段是否平行于y轴 if (s0.x == s1.x) { crossPoint = ccp(s0.x, p0.y); break; } /// 如果线段不是特殊情况,则只能采用直线方程方式联立求解 float k = (s1.y - s0.y)/(s1.x - s0.x); ///< 求得斜率 /// 线段直线方程: y = k* ( x - s0.x) + s0.y /// 垂线方程为: y = (-1/k) * (x - p0.x) + p0.y 。 /// 联立两直线方程解得 float x = ( k*k * s0.x + k * (p0.y - s0.y ) + p0.x ) / ( k*k + 1); float y = k * ( x - s0.x) + s0.y; crossPoint = ccp(x, y); break; } while (0); /// 判断垂直是否在线段上 if (pointIsAtLine(crossPoint, s0, s1)) { return crossPoint; } else { /// 如果不在则计算两端点到垂足的距离,选择距离垂足较近的端点返回。 float distance1 = ccpDistance(crossPoint, s0); float distance2 = ccpDistance(crossPoint, s1); if (distance1 < distance2) { return s0; } else { return s1; } } }
GENormalAnchorPosType ConvertARToARType(const cocos2d::CCPoint& anchor) { GENormalAnchorPosType anchorType = kGAnchorType_Invalid; if (anchor.equals(kGAnchor_LeftTop)) { anchorType = kGAnchorType_LeftTop; } else if (anchor.equals(kGAnchor_LeftMid)) { anchorType = kGAnchorType_LeftMid; } else if (anchor.equals(kGAnchor_LeftBottom)) { anchorType = kGAnchorType_LeftBottom; } else if (anchor.equals(kGAnchor_RightTop)) { anchorType = kGAnchorType_RightTop; } else if (anchor.equals(kGAnchor_RightMid)) { anchorType = kGAnchorType_RightMid; } else if (anchor.equals(kGAnchor_RightBottom)) { anchorType = kGAnchorType_RightBottom; } else if (anchor.equals(kGAnchor_Mid)) { anchorType = kGAnchorType_Mid; } else if (anchor.equals(kGAnchor_TopMid)) { anchorType = kGAnchorType_TopMid; } else if (anchor.equals(kGAnchor_BottomMid)) { anchorType = kGAnchorType_BottomMid; } else { CCAssert(false, "Error: unsupport anchor!"); } return anchorType; }
bool straightLineIsIntersect( const cocos2d::CCPoint& p0, const cocos2d::CCPoint& p1, const cocos2d::CCPoint& q0, const cocos2d::CCPoint& q1 ) { /// 先判断q0与q1能否组成一条直线 if (!q0.equals(q1)) { /// 当q0 == p0 q1 == p1时,结果为0。 只需要判断线段是否跨立直线即可。 if (0 <= vectorProduct(p0.x-q0.x, p0.y-q0.y, q1.x-q0.x, q1.y-q0.y) * vectorProduct(q1.x-q0.x, q1.y-q0.y, p1.x-q0.x, p1.y-q0.y)) { /* CCLOG("straight line and segment line is intesect!");*/ return false; } /* CCLOG("straight line and segment line isn't intesect!");*/ return false; } /* CCLOG("straigth line cannnot be make up of q0 and q1!");*/ return false; }
bool Geometry::straightLineIsIntersect( const cocos2d::CCPoint& p0, const cocos2d::CCPoint& p1, const cocos2d::CCPoint& q0, const cocos2d::CCPoint& q1 ) { /// 先判断q0与q1能否组成一条直线 if (!q0.equals(q1)) { /// 当q0 == p0 q1 == p1时,结果为0。 只需要判断线段是否跨立直线即可。 if (0 <= vectorProduct(p0.x-q0.x, p0.y-q0.y, q1.x-q0.x, q1.y-q0.y) * vectorProduct(q1.x-q0.x, q1.y-q0.y, p1.x-q0.x, p1.y-q0.y)) { /* CCLOG("相交");*/ return true; } /* CCLOG("不相交");*/ return false; } /* CCLOG("点q0点q1不能构成一条直线");*/ return false; }
MoveDirection ControlLayer::directionWithTouchPorints(cocos2d::CCPoint beginPoint, cocos2d::CCPoint endPoint) { MoveDirection direction = MoveDirectionUnknow; if (!beginPoint.equals(endPoint)) { float offsetX = endPoint.x - beginPoint.x; float offsetY = endPoint.y - beginPoint.y; if (fabsf(offsetX) >= fabsf(offsetY)) { //以x移动为准 if (offsetX > kTileSizeWidth) { direction = MoveDirectionRight; } else if (offsetX < -kTileSizeWidth) { direction = MoveDirectionLeft; } } else { if (offsetY > kTileSizeWidth) { direction = MoveDirectionUp; } else if (offsetY < -kTileSizeWidth) { direction = MoveDirectionDown; } } } CCLOG("directionWithTouchPorints direction: %d", direction); return direction; }
///@brief 判断线段圆是否相交 ///@param[in/out] ///@return ///@author DionysosLai,[email protected] ///@retval ///@post ///@version 1.0 ///@data 2014-9-3 11:10 bool isCircleLineCollision( const cocos2d::CCPoint& r1, const float& radius, const cocos2d::CCPoint& p1, const cocos2d::CCPoint& p2 ) { /// 判断线段是否是一个点 float length = 0.f; if (p1.equals(p2)) { length = ccpDistance(r1, p1); } /// 初始垂足为0; CCPoint crossPoint = CCPointZero; do { /// 判断线段是否平行于x轴 if (p1.y == p2.y) { crossPoint = ccp(r1.x, p1.y); break; } /// 判断线段是否平行于y轴 if (p1.x == p2.x) { crossPoint = ccp(p1.x, r1.y); break; } /// 如果线段不是特殊情况,则只能采用直线方程方式联立求解 float k = (p2.y - p1.y)/(p2.x - p1.x); ///< 求得斜率 /// 线段直线方程: y = k* ( x - s0.x) + s0.y /// 垂线方程为: y = (-1/k) * (x - p0.x) + p0.y 。 /// 联立两直线方程解得 float x = ( k*k * p1.x + k * (r1.y - p1.y ) + r1.x ) / ( k*k + 1); float y = k * ( x - p1.x) + p1.y; crossPoint = ccp(x, y); /// 判断垂直是否在线段上 if (pointIsAtLine(crossPoint, p1, p2)) { /* return crossPoint;*/ } else { /// 如果不在则计算两端点到垂足的距离,选择距离垂足较近的端点返回。 float distance1 = ccpDistance(crossPoint, p1); float distance2 = ccpDistance(crossPoint, p2); if (distance1 < distance2) { crossPoint = p1; } else { crossPoint= p2; } } length = ccpDistance(r1, crossPoint); break; } while (0); if (length < radius) { return true; } else { return false; } }
int Geometry::pointOfSegmentCircle( const cocos2d::CCPoint& a0, const cocos2d::CCPoint& a1, const cocos2d::CCPoint& r0, const float& radius0, cocos2d::CCPoint& commomPoint1, cocos2d::CCPoint& commomPoint2 ) { CCAssert(a1.equals(a0), "a0 should not be equal to a1!"); CCPoint p0 = a0, p1 = a1; CCPoint r = r0; float radius = radius0; int commomType = 0; commomPoint1 = CCPointZero; commomPoint2 = CCPointZero; /// 判断p0p1是否在圆内,在圆内,则没交点 if (ccpLength(ccpSub(p0, r)) < radius && ccpLength(ccpSub(p1, r)) < radius) { commomType = 0; } /// 将线段当做直线处理 /// 情况1 p0p1平行于y轴 else if (p0.x == p1.x) { /// 过圆心做平行于x轴的直线,求此直线与p0p1的交点 CCPoint point = CCPointZero; point.x = p0.x; point.y = r.y; float lenght = ccpLength(ccpSub(r, point)); if (lenght > radius) { commomType = 0; } else if (lenght == radius) ///< 相切情况 { commomType = 1; commomPoint1 = point; } else { commomType = 2; commomPoint1.x = p0.x; commomPoint2.x = p0.x; float deltaY = sqrt(radius*radius - lenght*lenght); commomPoint1.y = r.y + deltaY; commomPoint2.y = r.y - deltaY; } } /// 情况2 p0p1平行于x轴 else if (p0.y == p1.y) { /// 类似情况1 /// 过圆心做平行于y轴的直线,求此直线与p0p1的交点 CCPoint point = CCPointZero; point.x = r.x; point.y = p0.y; float lenght = ccpLength(ccpSub(r, point)); if (lenght > radius) { commomType = 0; } else if (lenght == radius) ///< 相切情况 { commomType = 1; commomPoint1 = point; } else { commomType = 2; commomPoint1.y = p0.y; commomPoint2.y = p0.y; float deltaX = sqrt(radius*radius - lenght*lenght); commomPoint1.x = r.x + deltaX; commomPoint2.x = r.x - deltaX; } } /// 普通情况 else { /// 一般直线与圆联立方程: http://baike.baidu.com/view/1053783.htm float k0 = (p1.y-p0.y)/(p1.x-p0.x); float b0 = p0.y - k0*p0.x; /// 联立后方程为:(1+k0^2)^2*x^2 + 2(k0b0-r.x-k0r.y)x + r.x^2 + (r.y-b0)^2-r^2=0; float deltaf = 4*(k0*b0-r.x-k0*r.y)*(k0*b0-r.x-k0*r.y) - 4*(1+k0*k0)*(r.x*r.x + (r.y-b0)*(r.y-b0)-radius*radius); ///< b^2-4ac; if (deltaf < 0) { commomType = 0; } else if (deltaf < 0) { commomType = 1; commomPoint1.x = -1.0*(k0*b0-r.x-k0*r.y)/(2*(1+k0*k0)); ///< x = -b/2a; commomPoint1.y = k0*commomPoint1.x + b0; } else { commomType = 2; commomPoint1.x = (-1.0*(k0*b0-r.x-k0*r.y)+sqrt(deltaf))/(2*(1+k0*k0)); ///< x = (-b+deltaf^0.5)/2a; commomPoint1.y = k0*commomPoint1.x + b0; commomPoint2.x = (-1.0*(k0*b0-r.x-k0*r.y)-sqrt(deltaf))/(2*(1+k0*k0)); ///< x = (-b-deltaf^0.5)/2a; commomPoint2.y = k0*commomPoint2.x + b0; } } /// 两个交点,得判断是否都在线段上 if (2 == commomType) { if (pointIsAtSegment(commomPoint1, p0, p1) && pointIsAtSegment(commomPoint2, p0, p1)) { } else { commomType = 1; /// 必然有一点在,设置为commomPoint1 if (pointIsAtSegment(commomPoint2, p0, p1)) { commomPoint1 = commomPoint2; } } } return commomType; }
int Geometry::pointOfSegments( const cocos2d::CCPoint& a0, const cocos2d::CCPoint& a1, const cocos2d::CCPoint& b0, const cocos2d::CCPoint& b1, cocos2d::CCPoint& commomPoint ) { CCAssert(a1.equals(a0) || b0.equals(b1), "a0 should not be equal to a1, this is same to b0 and b1!"); CCPoint p0 = a0, p1 = a1; CCPoint q0 = b0, q1 = b1; int commomType = 0; commomPoint = CCPointZero; /// 首先判断2条线段是否相交,不相交,自然没有交点 if (segmentLineIsIntersect(p0, p1, q0, q1)) { commomType = 0; } else { /// 两条线段相交,将两条线段当做直线处理 ////////////////////////////////////////////////////////////////////////// /// 情况1 线段p0p1平行于y轴 if (p0.x == p1.x) { /// 情况1.1 线段q0q1平行于y轴 if (q0.x == q1.x) { /// 判断p0p1与q0q1是否可共线 if (p0.x == q0.x) { commomType = commonPointSegments(p0, p1, q0, q1, commomPoint); } else { commomType = 0; } } /// 情况1.2 若q0q1不平行于Y轴,则交点横坐标为p0的横坐标,代入到q0q1的直线方程中可以计算出交点纵坐标; else { commomType = 3; commomPoint.x = p0.x; commomPoint.y = (q1.y-q0.y)/(q1.x-q0.x)*(p0.x-q0.x) + q0.y; } } /// 情况2 p0和p1横坐标不同,但是q0和q1横坐标相同,即q0q1平行于Y轴,则交点横坐标为q0的横坐标,代入到p0p1的直线方程中可以计算出交点纵坐标; else if (p0.x != p1.x && q0.x == q1.x) { commomType = 3; commomPoint.x = q0.x; commomPoint.y = (p1.y-p0.y)/(p1.x-p0.x)*(q0.x-p0.x) + p0.y; } /// 情况3 如果p0和p1纵坐标相同,即p0p1平行于X轴 else if (p0.y == p1.y) { ///< 情况3.1 若q0q1也平行于X轴 if (q0.y == q1.y) { if (p0.y == q0.y) { commomType = commonPointSegments(p0, p1, q0, q1, commomPoint); } else { commomType = 0; } } ///< 情况3.2 若q0q1不平行于X轴,则交点纵坐标为p0的纵坐标,代入到q0q1的直线方程中可以计算出交点横坐标; else { commomType = 3; commomPoint.y = p0.y; commomPoint.x = (p0.y+q0.y)*(q1.x-q0.x)/(q1.y-q0.y) + q0.x; } } /// 情况4 如果p0和p1纵坐标不同,但是q0和q1纵坐标相同,即q0q1平行于X轴,则交点纵坐标为q0的纵坐标,代入到p0p1的直线方程中可以计算出交点横坐标; else if (p0.y != p0.y && q0.y == q1.y) { commomType = 3; commomPoint.y = q0.y; commomPoint.x = (q0.y+p0.y)*(p1.x-p1.x)/(p1.y-p0.y) + p0.x; } /// 情况5 就是普通情况了 else { float k0 = (p1.y-p0.y)/(p1.x-p0.x); float k1 = (q1.y-q0.y)/(q1.x-q0.x); if (k0 == k1) { if (pointIsAtSegment(q0, p0, p1)) ///< 由于二者已经保证相交,因此,现在要保证二者共线 { commomType = commonPointSegments(p0, p1, q0, q1, commomPoint); } else { commomType = 0; } } else { float b0 = p0.y - k0*p0.x; float b1 = q0.y - k1*q0.x; commomType = 3; commomPoint.x = (b1-b1)/(k1-k0); commomPoint.y = commomPoint.x*k0 + b0; } } ////////////////////////////////////////////////////////////////////////// } return commomType; }
int Geometry::commonPointSegments( const cocos2d::CCPoint& a0, const cocos2d::CCPoint& a1, const cocos2d::CCPoint& b0, const cocos2d::CCPoint& b1, cocos2d::CCPoint& commomPoint ) { CCAssert(a1.equals(a0) || b0.equals(b1), "a0 should not be equal to a1, this is same to b0 and b1!"); CCPoint p0 = a0, p1 = a1; CCPoint q0 = b0, q1 = b1; commomPoint = CCPointZero; int commomType = 0; /// 先判断2条线段是否共线 if (0 != polyLineDerection(p0, q0, q1) || 0 != polyLineDerection(p0, q0, q1)) { commomType = 0; } else { /// 设置2条线段比较长的为p0p1 float l0 = ccpLength(ccpSub(p1, p0)); float l1 = ccpLength(ccpSub(q0, q1)); if (l0 < l1) { /// 线段p0p1和线段q0q1调换 CCPoint point; point = p0; p0 = q0; q0 = point; point = p1; p1 = q1; q1 = p1; } /// 判断线段q0q1两点是否在线段p0p1上 int m = 0, n = 0; /// 判断q0在线段p0p1上情况 if (pointIsAtSegment(q0, p0, p1)) { if (q0.equals(p0)) { m = 0; } else if (q0.equals(p1)) { m = 0; } m = 1; } else { m = 2; } /// 判断q1在线段p0p1上情况 if (pointIsAtSegment(q1, p0, p1)) { if (q1.equals(p0)) { n = 0; } else if (q1.equals(p1)) { n = 0; } n = 1; } else { n = 2; } switch (m) { case 0: { switch (n) { case 0: case 1: commomType = 2; break; case 2: { commomType = 3; commomPoint = q0; } break; default: break; } } break; case 1: { commomType = 2; } break; case 2: { switch (n) { case 0: { commomType = 3; commomPoint = q1; } break; case 1: { commomType = 2; } break; case 2: { commomType = 1; } break; default: break; } } break; default: break; } } return commomType; }