/** Copyright 2013 BlackBerry Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Original file from GamePlay3D: http://gameplay3d.org This file was modified to fit the cocos2d-x project */ #include "Vector2.h" #include "base/ccMacros.h" #include "MathUtil.h" NS_CC_MATH_BEGIN // returns true if segment A-B intersects with segment C-D. S->E is the ovderlap part bool isOneDimensionSegmentOverlap(float A, float B, float C, float D, float *S, float * E) { float ABmin = MIN(A, B); float ABmax = MAX(A, B); float CDmin = MIN(C, D); float CDmax = MAX(C, D); if (ABmax < CDmin || CDmax < ABmin) { // ABmin->ABmax->CDmin->CDmax or CDmin->CDmax->ABmin->ABmax return false; } else { if (ABmin >= CDmin && ABmin <= CDmax) { // CDmin->ABmin->CDmax->ABmax or CDmin->ABmin->ABmax->CDmax if (S != nullptr) *S = ABmin; if (E != nullptr) *E = CDmax < ABmax ? CDmax : ABmax; } else if (ABmax >= CDmin && ABmax <= CDmax) { // ABmin->CDmin->ABmax->CDmax if (S != nullptr) *S = CDmin; if (E != nullptr) *E = ABmax; } else { // ABmin->CDmin->CDmax->ABmax if (S != nullptr) *S = CDmin; if (E != nullptr) *E = CDmax; } return true; } } // cross procuct of 2 vector. A->B X C->D float crossProduct2Vector(const Vector2& A, const Vector2& B, const Vector2& C, const Vector2& D) { return (D.y - C.y) * (B.x - A.x) - (D.x - C.x) * (B.y - A.y); } Vector2::Vector2() : x(0.0f), y(0.0f) { } Vector2::Vector2(float xx, float yy) : x(xx), y(yy) { } Vector2::Vector2(const float* array) { set(array); } Vector2::Vector2(const Vector2& p1, const Vector2& p2) { set(p1, p2); } Vector2::Vector2(const Vector2& copy) { set(copy); } Vector2::~Vector2() { } const Vector2& Vector2::zero() { static Vector2 value(0.0f, 0.0f); return value; } const Vector2& Vector2::one() { static Vector2 value(1.0f, 1.0f); return value; } const Vector2& Vector2::unitX() { static Vector2 value(1.0f, 0.0f); return value; } const Vector2& Vector2::unitY() { static Vector2 value(0.0f, 1.0f); return value; } bool Vector2::isZero() const { return x == 0.0f && y == 0.0f; } bool Vector2::isOne() const { return x == 1.0f && y == 1.0f; } float Vector2::angle(const Vector2& v1, const Vector2& v2) { float dz = v1.x * v2.y - v1.y * v2.x; return atan2f(fabsf(dz) + MATH_FLOAT_SMALL, dot(v1, v2)); } void Vector2::add(const Vector2& v) { x += v.x; y += v.y; } void Vector2::add(const Vector2& v1, const Vector2& v2, Vector2* dst) { GP_ASSERT(dst); dst->x = v1.x + v2.x; dst->y = v1.y + v2.y; } void Vector2::clamp(const Vector2& min, const Vector2& max) { GP_ASSERT(!(min.x > max.x || min.y > max.y )); // Clamp the x value. if (x < min.x) x = min.x; if (x > max.x) x = max.x; // Clamp the y value. if (y < min.y) y = min.y; if (y > max.y) y = max.y; } void Vector2::clamp(const Vector2& v, const Vector2& min, const Vector2& max, Vector2* dst) { GP_ASSERT(dst); GP_ASSERT(!(min.x > max.x || min.y > max.y )); // Clamp the x value. dst->x = v.x; if (dst->x < min.x) dst->x = min.x; if (dst->x > max.x) dst->x = max.x; // Clamp the y value. dst->y = v.y; if (dst->y < min.y) dst->y = min.y; if (dst->y > max.y) dst->y = max.y; } float Vector2::distance(const Vector2& v) const { float dx = v.x - x; float dy = v.y - y; return sqrt(dx * dx + dy * dy); } float Vector2::distanceSquared(const Vector2& v) const { float dx = v.x - x; float dy = v.y - y; return (dx * dx + dy * dy); } float Vector2::dot(const Vector2& v) const { return (x * v.x + y * v.y); } float Vector2::dot(const Vector2& v1, const Vector2& v2) { return (v1.x * v2.x + v1.y * v2.y); } float Vector2::length() const { return sqrt(x * x + y * y); } float Vector2::lengthSquared() const { return (x * x + y * y); } void Vector2::negate() { x = -x; y = -y; } void Vector2::normalize() { float n = x * x + y * y; // Already normalized. if (n == 1.0f) return; n = sqrt(n); // Too close to zero. if (n < MATH_TOLERANCE) return; n = 1.0f / n; x *= n; y *= n; } Vector2 Vector2::getNormalized() const { Vector2 v(*this); v.normalize(); return v; } void Vector2::scale(float scalar) { x *= scalar; y *= scalar; } void Vector2::scale(const Vector2& scale) { x *= scale.x; y *= scale.y; } void Vector2::rotate(const Vector2& point, float angle) { double sinAngle = sin(angle); double cosAngle = cos(angle); if (point.isZero()) { float tempX = x * cosAngle - y * sinAngle; y = y * cosAngle + x * sinAngle; x = tempX; } else { float tempX = x - point.x; float tempY = y - point.y; x = tempX * cosAngle - tempY * sinAngle + point.x; y = tempY * cosAngle + tempX * sinAngle + point.y; } } void Vector2::set(float xx, float yy) { this->x = xx; this->y = yy; } void Vector2::set(const float* array) { GP_ASSERT(array); x = array[0]; y = array[1]; } void Vector2::set(const Vector2& v) { this->x = v.x; this->y = v.y; } void Vector2::set(const Vector2& p1, const Vector2& p2) { x = p2.x - p1.x; y = p2.y - p1.y; } void Vector2::subtract(const Vector2& v) { x -= v.x; y -= v.y; } void Vector2::subtract(const Vector2& v1, const Vector2& v2, Vector2* dst) { GP_ASSERT(dst); dst->x = v1.x - v2.x; dst->y = v1.y - v2.y; } void Vector2::smooth(const Vector2& target, float elapsedTime, float responseTime) { if (elapsedTime > 0) { *this += (target - *this) * (elapsedTime / (elapsedTime + responseTime)); } } void Vector2::setPoint(float xx, float yy) { this->x = xx; this->y = yy; } bool Vector2::equals(const Vector2& target) const { return (fabs(this->x - target.x) < FLT_EPSILON) && (fabs(this->y - target.y) < FLT_EPSILON); } bool Vector2::fuzzyEquals(const Vector2& b, float var) const { if(x - var <= b.x && b.x <= x + var) if(y - var <= b.y && b.y <= y + var) return true; return false; } float Vector2::getAngle(const Vector2& other) const { Vector2 a2 = getNormalized(); Vector2 b2 = other.getNormalized(); float angle = atan2f(a2.cross(b2), a2.dot(b2)); if( fabs(angle) < FLT_EPSILON ) return 0.f; return angle; } Vector2 Vector2::rotateByAngle(const Vector2& pivot, float angle) const { return pivot + (*this - pivot).rotate(Vector2::forAngle(angle)); } bool Vector2::isLineIntersect(const Vector2& A, const Vector2& B, const Vector2& C, const Vector2& D, float *S, float *T) { // FAIL: Line undefined if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) { return false; } const float denom = crossProduct2Vector(A, B, C, D); if (denom == 0) { // Lines parallel or overlap return false; } if (S != nullptr) *S = crossProduct2Vector(C, D, C, A) / denom; if (T != nullptr) *T = crossProduct2Vector(A, B, C, A) / denom; return true; } bool Vector2::isLineParallel(const Vector2& A, const Vector2& B, const Vector2& C, const Vector2& D) { // FAIL: Line undefined if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) { return false; } if (crossProduct2Vector(A, B, C, D) == 0) { // line overlap if (crossProduct2Vector(C, D, C, A) == 0 || crossProduct2Vector(A, B, C, A) == 0) { return false; } return true; } return false; } bool Vector2::isLineOverlap(const Vector2& A, const Vector2& B, const Vector2& C, const Vector2& D) { // FAIL: Line undefined if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) ) { return false; } if (crossProduct2Vector(A, B, C, D) == 0 && (crossProduct2Vector(C, D, C, A) == 0 || crossProduct2Vector(A, B, C, A) == 0)) { return true; } return false; } bool Vector2::isSegmentOverlap(const Vector2& A, const Vector2& B, const Vector2& C, const Vector2& D, Vector2* S, Vector2* E) { if (isLineOverlap(A, B, C, D)) { return isOneDimensionSegmentOverlap(A.x, B.x, C.x, D.x, &S->x, &E->x) && isOneDimensionSegmentOverlap(A.y, B.y, C.y, D.y, &S->y, &E->y); } return false; } bool Vector2::isSegmentIntersect(const Vector2& A, const Vector2& B, const Vector2& C, const Vector2& D) { float S, T; if (isLineIntersect(A, B, C, D, &S, &T )&& (S >= 0.0f && S <= 1.0f && T >= 0.0f && T <= 1.0f)) { return true; } return false; } Vector2 Vector2::getIntersectPoint(const Vector2& A, const Vector2& B, const Vector2& C, const Vector2& D) { float S, T; if (isLineIntersect(A, B, C, D, &S, &T)) { // Vector2 of intersection Vector2 P; P.x = A.x + S * (B.x - A.x); P.y = A.y + S * (B.y - A.y); return P; } return Vector2::ZERO; } const Vector2 Vector2::ZERO = Vector2(0.0f, 0.0f); const Vector2 Vector2::ANCHOR_MIDDLE = Vector2(0.5f, 0.5f); const Vector2 Vector2::ANCHOR_BOTTOM_LEFT = Vector2(0.0f, 0.0f); const Vector2 Vector2::ANCHOR_TOP_LEFT = Vector2(0.0f, 1.0f); const Vector2 Vector2::ANCHOR_BOTTOM_RIGHT = Vector2(1.0f, 0.0f); const Vector2 Vector2::ANCHOR_TOP_RIGHT = Vector2(1.0f, 1.0f); const Vector2 Vector2::ANCHOR_MIDDLE_RIGHT = Vector2(1.0f, 0.5f); const Vector2 Vector2::ANCHOR_MIDDLE_LEFT = Vector2(0.0f, 0.5f); const Vector2 Vector2::ANCHOR_MIDDLE_TOP = Vector2(0.5f, 1.0f); const Vector2 Vector2::ANCHOR_MIDDLE_BOTTOM = Vector2(0.5f, 0.0f); NS_CC_MATH_END