package com.junerking.particle; public class CGPoint { private static final float kCGPointEpsilon = 0.00000012f; public float x, y; private static final CGPoint tmp = new CGPoint(0, 0); public static CGPoint tmp() { return tmp; } private static final CGPoint ZERO_POINT = new CGPoint(0, 0); public static CGPoint getZero() { return ZERO_POINT; } public static CGPoint zero() { return new CGPoint(0, 0); } public static CGPoint make(float x, float y) { return new CGPoint(x, y); } public CGPoint() { this(0, 0); } private CGPoint(float x, float y) { this.x = x; this.y = y; } /** * Set value */ public CGPoint set(float x, float y) { this.x = x; this.y = y; return this; } public CGPoint set(CGPoint p) { this.x = p.x; this.y = p.y; return this; } public String toString() { return "(" + x + ", " + y + ")"; } public static boolean equalToPoint(CGPoint p1, CGPoint p2) { return p1.x == p2.x && p1.y == p2.y; } /** * Helper macro that creates a CCPoint * * @return CCPoint */ public static CGPoint ccp(float x, float y) { return new CGPoint(x, y); } /** * Returns opposite of point. * * @return CCPoint */ public static CGPoint ccpNeg(final CGPoint v) { return ccp(-v.x, -v.y); } /** * Calculates sum of two points. * * @return CCPoint */ public static CGPoint ccpAdd(final CGPoint v1, final CGPoint v2) { return ccp(v1.x + v2.x, v1.y + v2.y); } /** * Calculates difference of two points. * * @return CCPoint */ public static CGPoint ccpSub(final CGPoint v1, final CGPoint v2) { return ccp(v1.x - v2.x, v1.y - v2.y); } /** * Returns point multiplied by given factor. * * @return CCPoint */ public static CGPoint ccpMult(final CGPoint v, final float s) { return ccp(v.x * s, v.y * s); } /** * Calculates midpoint between two points. * * @return CCPoint */ public static CGPoint ccpMidpoint(final CGPoint v1, final CGPoint v2) { return ccpMult(ccpAdd(v1, v2), 0.5f); } /** * Calculates dot product of two points. * * @return float */ public static float ccpDot(final CGPoint v1, final CGPoint v2) { return v1.x * v2.x + v1.y * v2.y; } /** * Calculates cross product of two points. * * @return float */ public static float ccpCross(final CGPoint v1, final CGPoint v2) { return v1.x * v2.y - v1.y * v2.x; } /** * Calculates perpendicular of v, rotated 90 degrees counter-clockwise -- cross(v, perp(v)) >= 0 * * @return CCPoint */ public static CGPoint ccpPerp(final CGPoint v) { return ccp(-v.y, v.x); } /** * Calculates perpendicular of v, rotated 90 degrees clockwise -- cross(v, rperp(v)) <= 0 * * @return CCPoint */ public static CGPoint ccpRPerp(final CGPoint v) { return ccp(v.y, -v.x); } /** * Calculates the projection of v1 over v2. * * @return CCPoint */ public static CGPoint ccpProject(final CGPoint v1, final CGPoint v2) { return ccpMult(v2, ccpDot(v1, v2) / ccpDot(v2, v2)); } /** * Rotates two points. * * @return CCPoint */ public static CGPoint ccpRotate(final CGPoint v1, final CGPoint v2) { return ccp(v1.x * v2.x - v1.y * v2.y, v1.x * v2.y + v1.y * v2.x); } /** * Unrotates two points. * * @return CCPoint */ public static CGPoint ccpUnrotate(final CGPoint v1, final CGPoint v2) { return ccp(v1.x * v2.x + v1.y * v2.y, v1.y * v2.x - v1.x * v2.y); } /** * Calculates the square length of a CCPoint (not calling sqrt() ) * * @return float */ public static float ccpLengthSQ(final CGPoint v) { return ccpDot(v, v); } /** * Calculates distance between point and origin * * @return CGFloat * @since v0.7.2 */ public static float ccpLength(final CGPoint v) { return (float) Math.sqrt(ccpLengthSQ(v)); } /** * Calculates the distance between two points * * @return float */ public static float ccpDistance(final CGPoint v1, final CGPoint v2) { return ccpLength(ccpSub(v1, v2)); } /** * Returns point multiplied to a length of 1. * * @return CCPoint */ public static CGPoint ccpNormalize(final CGPoint v) { return ccpMult(v, 1.0f / ccpLength(v)); } /** * Converts radians to a normalized vector. * * @return CCPoint */ public static CGPoint ccpForAngle(final float a) { return ccp((float) Math.cos(a), (float) Math.sin(a)); } /** * Converts a vector to radians. * * @return float */ public static float ccpToAngle(final CGPoint v) { return (float) Math.atan2(v.y, v.x); } /** * Caculate the rotation(in degrees) between two points, so that when we move from one point to the other, we can * set the correct rotation to head to that point. * * @param from * @param to * @return the rotation in degrees */ public static float ccpCalcRotate(final CGPoint from, final CGPoint to) { float o = to.x - from.x; float a = to.y - from.y; float at = CC_RADIANS_TO_DEGREES((float) Math.atan(o / a)); if (a < 0) { if (o < 0) at = 180 + Math.abs(at); else at = 180 - Math.abs(at); } return at; } public static final float CC_RADIANS_TO_DEGREES(float angle) { return (angle / (float) Math.PI * 180.0f); } /** * @returns the angle in radians between two vector directions * @since v0.99.1 */ public static float ccpAngle(CGPoint a, CGPoint b) { float angle = (float) Math.acos(ccpDot(ccpNormalize(a), ccpNormalize(b))); if (Math.abs(angle) < kCGPointEpsilon) return 0.f; return angle; } /** * Linear Interpolation between two points a and b * * @returns alpha == 0 ? a alpha == 1 ? b otherwise a value between a..b * @since v0.99.1 */ public static CGPoint ccpLerp(CGPoint a, CGPoint b, float alpha) { return ccpAdd(ccpMult(a, 1.f - alpha), ccpMult(b, alpha)); } /** * Clamp a value between from and to. * * @since v0.99.1 */ public static float clampf(float value, float min_inclusive, float max_inclusive) { if (min_inclusive > max_inclusive) { float tmp = min_inclusive; min_inclusive = max_inclusive; max_inclusive = tmp; } return value < min_inclusive ? min_inclusive : value < max_inclusive ? value : max_inclusive; } /** * Clamp a point between from and to. * * @since v0.99.1 */ public static CGPoint ccpClamp(CGPoint p, CGPoint min_inclusive, CGPoint max_inclusive) { return ccp(clampf(p.x, min_inclusive.x, max_inclusive.x), clampf(p.y, min_inclusive.y, max_inclusive.y)); } /** * @returns if points have fuzzy equality which means equal with some degree of variance. * @since v0.99.1 */ public static boolean ccpFuzzyEqual(CGPoint a, CGPoint b, float var) { if (a.x - var <= b.x && b.x <= a.x + var) if (a.y - var <= b.y && b.y <= a.y + var) return true; return false; } /** * Multiplies a nd b components, a.x*b.x, a.y*b.y * * @returns a component-wise multiplication * @since v0.99.1 */ public static CGPoint ccpCompMult(CGPoint a, CGPoint b) { return ccp(a.x * b.x, a.y * b.y); } /** * @returns the signed angle in radians between two vector directions * @since v0.99.1 */ public static float ccpAngleSigned(CGPoint a, CGPoint b) { CGPoint a2 = ccpNormalize(a); CGPoint b2 = ccpNormalize(b); float angle = (float) Math.atan2(a2.x * b2.y - a2.y * b2.x, ccpDot(a2, b2)); if (Math.abs(angle) < kCGPointEpsilon) return 0.f; return angle; } /** * Rotates a point counter clockwise by the angle around a pivot * * @param v * is the point to rotate * @param pivot * is the pivot, naturally * @param angle * is the angle of rotation cw in radians * @returns the rotated point * @since v0.99.1 */ public static CGPoint ccpRotateByAngle(CGPoint v, CGPoint pivot, float angle) { CGPoint r = ccpSub(v, pivot); float t = r.x; float cosa = (float) Math.cos(angle); float sina = (float) Math.sin(angle); r.x = t * cosa - r.y * sina; r.y = t * sina + r.y * cosa; r = ccpAdd(r, pivot); return r; } /** * A general line-line intersection test * * @param p1 * is the startpoint for the first line P1 = (p1 - p2) * @param p2 * is the endpoint for the first line P1 = (p1 - p2) * @param p3 * is the startpoint for the second line P2 = (p3 - p4) * @param p4 * is the endpoint for the second line P2 = (p3 - p4) * @param s * is the range for a hitpoint in P1 (pa = p1 + s*(p2 - p1)) * @param t * is the range for a hitpoint in P3 (pa = p2 + t*(p4 - p3)) * @return bool indicating successful intersection of a line note that to truly test intersection for segments we * have to make sure that s & t lie within [0..1] and for rays, make sure s & t > 0 the hit point is p3 + t * * (p4 - p3); the hit point also is p1 + s * (p2 - p1); * @since v0.99.1 */ public static boolean ccpLineIntersect(CGPoint p1, CGPoint p2, CGPoint p3, CGPoint p4, CGPoint ret) { CGPoint p13, p43, p21; float d1343, d4321, d1321, d4343, d2121; float numer, denom; p13 = ccpSub(p1, p3); p43 = ccpSub(p4, p3); //Roughly equal to zero but with an epsilon deviation for float //correction if (ccpFuzzyEqual(p43, CGPoint.zero(), kCGPointEpsilon)) return false; p21 = ccpSub(p2, p1); //Roughly equal to zero if (ccpFuzzyEqual(p21, CGPoint.zero(), kCGPointEpsilon)) return false; d1343 = ccpDot(p13, p43); d4321 = ccpDot(p43, p21); d1321 = ccpDot(p13, p21); d4343 = ccpDot(p43, p43); d2121 = ccpDot(p21, p21); denom = d2121 * d4343 - d4321 * d4321; if (Math.abs(denom) < kCGPointEpsilon) return false; numer = d1343 * d4321 - d1321 * d4343; ret.x = numer / denom; ret.y = (d1343 + d4321 * ret.x) / d4343; return true; } }