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