1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17
18package com.replica.replicaisland;
19
20/** A sphere collision volume. */
21public class SphereCollisionVolume extends CollisionVolume {
22    private float mRadius;
23    private Vector2 mCenter;
24    private Vector2 mWorkspaceVector;
25    private Vector2 mWorkspaceVector2;
26
27    public SphereCollisionVolume(float radius, float centerX, float centerY) {
28        super();
29        mRadius = radius;
30        mCenter = new Vector2(centerX, centerY);
31        mWorkspaceVector = new Vector2();
32        mWorkspaceVector2 = new Vector2();
33    }
34
35    public SphereCollisionVolume(float radius, float centerX, float centerY, int hit) {
36        super(hit);
37        mRadius = radius;
38        mCenter = new Vector2(centerX, centerY);
39        mWorkspaceVector = new Vector2();
40        mWorkspaceVector2 = new Vector2();
41    }
42
43    @Override
44    public float getMaxX() {
45        return mCenter.x + mRadius;
46    }
47
48    @Override
49    public float getMinX() {
50        return mCenter.x - mRadius;
51    }
52
53    @Override
54    public float getMaxY() {
55        return mCenter.y + mRadius;
56    }
57
58    @Override
59    public float getMinY() {
60        return mCenter.y - mRadius;
61    }
62
63    public Vector2 getCenter() {
64        return mCenter;
65    }
66
67    public void setCenter(Vector2 center) {
68        mCenter.set(center);
69    }
70
71    public float getRadius() {
72        return mRadius;
73    }
74
75    public void setRadius(float radius) {
76        mRadius = radius;
77    }
78
79    public void reset() {
80        mCenter.zero();
81        mRadius = 0;
82    }
83
84    @Override
85    public boolean intersects(Vector2 position, FlipInfo flip, CollisionVolume other,
86            Vector2 otherPosition, FlipInfo otherFlip) {
87        boolean result = false;
88
89        if (other instanceof AABoxCollisionVolume) {
90            // It's more accurate to do a sphere-as-box test than a box-as-sphere test.
91            result = other.intersects(otherPosition, otherFlip, this, position, flip);
92        } else {
93            mWorkspaceVector.set(position);
94            offsetByCenter(mWorkspaceVector, mCenter, flip);
95
96            float otherRadius = 0;
97            if (other instanceof SphereCollisionVolume) {
98                SphereCollisionVolume sphereOther = (SphereCollisionVolume)other;
99                mWorkspaceVector2.set(otherPosition);
100                offsetByCenter(mWorkspaceVector2, sphereOther.getCenter(), otherFlip);
101                mWorkspaceVector.subtract(mWorkspaceVector2);
102                otherRadius = sphereOther.getRadius();
103            } else {
104                // Whatever this volume is, pretend it's a sphere.
105                final float deltaX = other.getMaxXPosition(otherFlip)
106                    - other.getMinXPosition(otherFlip);
107                final float deltaY = other.getMaxYPosition(otherFlip)
108                    - other.getMinYPosition(otherFlip);
109                final float centerX = deltaX / 2.0f;
110                final float centerY = deltaY / 2.0f;
111
112                mWorkspaceVector2.set(otherPosition);
113                mWorkspaceVector2.x += centerX;
114                mWorkspaceVector2.y += centerY;
115                otherRadius = Math.max(deltaX, deltaY);
116            }
117
118            final float maxDistance = mRadius + otherRadius;
119            final float distance2 = mWorkspaceVector.length2();
120            final float maxDistance2 = (maxDistance * maxDistance);
121            if (distance2 < maxDistance2) {
122                result = true;
123            }
124        }
125
126        return result;
127    }
128
129    public void growBy(CollisionVolume other) {
130        final float maxX;
131        final float minX;
132
133        final float maxY;
134        final float minY;
135
136        if (mRadius > 0) {
137            maxX = Math.max(getMaxX(), other.getMaxX());
138            minX = Math.min(getMinX(), other.getMinX());
139            maxY = Math.max(getMaxY(), other.getMaxY());
140            minY = Math.min(getMinY(), other.getMinY());
141        } else {
142            maxX = other.getMaxX();
143            minX = other.getMinX();
144            maxY = other.getMaxY();
145            minY = other.getMinY();
146        }
147        final float horizontalDelta = maxX - minX;
148        final float verticalDelta = maxY - minY;
149        final float diameter = Math.max(horizontalDelta, verticalDelta);
150
151        final float newCenterX = minX + (horizontalDelta / 2.0f);
152        final float newCenterY = minY + (verticalDelta / 2.0f);
153        final float newRadius = diameter / 2.0f;
154
155        mCenter.set(newCenterX, newCenterY);
156        mRadius = newRadius;
157    }
158
159    private static void offsetByCenter(Vector2 position, Vector2 center, FlipInfo flip) {
160        if (flip != null && (flip.flipX || flip.flipY)) {
161            if (flip.flipX) {
162                position.x += flip.parentWidth - center.x;
163            } else {
164                position.x += center.x;
165            }
166
167            if (flip.flipY) {
168                position.y += flip.parentHeight - center.y;
169            } else {
170                position.y += center.y;
171            }
172        } else {
173            position.add(center);
174        }
175    }
176
177}
178