1/*
2 * Copyright (c) 2009-2010 jMonkeyEngine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 *   notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 *   notice, this list of conditions and the following disclaimer in the
14 *   documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 *   may be used to endorse or promote products derived from this software
18 *   without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33package com.jme3.math;
34
35import com.jme3.export.*;
36import java.io.IOException;
37
38
39/**
40 * <code>Ring</code> defines a flat ring or disk within three dimensional
41 * space that is specified via the ring's center point, an up vector, an inner
42 * radius, and an outer radius.
43 *
44 * @author Andrzej Kapolka
45 * @author Joshua Slack
46 */
47
48public final class Ring implements Savable, Cloneable, java.io.Serializable {
49
50    static final long serialVersionUID = 1;
51
52    private Vector3f center, up;
53    private float innerRadius, outerRadius;
54    private transient static Vector3f b1 = new Vector3f(), b2 = new Vector3f();
55
56    /**
57     * Constructor creates a new <code>Ring</code> lying on the XZ plane,
58     * centered at the origin, with an inner radius of zero and an outer radius
59     * of one (a unit disk).
60     */
61    public Ring() {
62        center = new Vector3f();
63        up = Vector3f.UNIT_Y.clone();
64        innerRadius = 0f;
65        outerRadius = 1f;
66    }
67
68    /**
69     * Constructor creates a new <code>Ring</code> with defined center point,
70     * up vector, and inner and outer radii.
71     *
72     * @param center
73     *            the center of the ring.
74     * @param up
75     *            the unit up vector defining the ring's orientation.
76     * @param innerRadius
77     *            the ring's inner radius.
78     * @param outerRadius
79     *            the ring's outer radius.
80     */
81    public Ring(Vector3f center, Vector3f up, float innerRadius,
82            float outerRadius) {
83        this.center = center;
84        this.up = up;
85        this.innerRadius = innerRadius;
86        this.outerRadius = outerRadius;
87    }
88
89    /**
90     * <code>getCenter</code> returns the center of the ring.
91     *
92     * @return the center of the ring.
93     */
94    public Vector3f getCenter() {
95        return center;
96    }
97
98    /**
99     * <code>setCenter</code> sets the center of the ring.
100     *
101     * @param center
102     *            the center of the ring.
103     */
104    public void setCenter(Vector3f center) {
105        this.center = center;
106    }
107
108    /**
109     * <code>getUp</code> returns the ring's up vector.
110     *
111     * @return the ring's up vector.
112     */
113    public Vector3f getUp() {
114        return up;
115    }
116
117    /**
118     * <code>setUp</code> sets the ring's up vector.
119     *
120     * @param up
121     *            the ring's up vector.
122     */
123    public void setUp(Vector3f up) {
124        this.up = up;
125    }
126
127    /**
128     * <code>getInnerRadius</code> returns the ring's inner radius.
129     *
130     * @return the ring's inner radius.
131     */
132    public float getInnerRadius() {
133        return innerRadius;
134    }
135
136    /**
137     * <code>setInnerRadius</code> sets the ring's inner radius.
138     *
139     * @param innerRadius
140     *            the ring's inner radius.
141     */
142    public void setInnerRadius(float innerRadius) {
143        this.innerRadius = innerRadius;
144    }
145
146    /**
147     * <code>getOuterRadius</code> returns the ring's outer radius.
148     *
149     * @return the ring's outer radius.
150     */
151    public float getOuterRadius() {
152        return outerRadius;
153    }
154
155    /**
156     * <code>setOuterRadius</code> sets the ring's outer radius.
157     *
158     * @param outerRadius
159     *            the ring's outer radius.
160     */
161    public void setOuterRadius(float outerRadius) {
162        this.outerRadius = outerRadius;
163    }
164
165    /**
166     *
167     * <code>random</code> returns a random point within the ring.
168     *
169     * @return a random point within the ring.
170     */
171    public Vector3f random() {
172        return random(null);
173    }
174
175    /**
176     *
177     * <code>random</code> returns a random point within the ring.
178     *
179     * @param result Vector to store result in
180     * @return a random point within the ring.
181     */
182    public Vector3f random(Vector3f result) {
183        if (result == null) {
184            result = new Vector3f();
185        }
186
187        // compute a random radius according to the ring area distribution
188        float inner2 = innerRadius * innerRadius, outer2 = outerRadius
189                * outerRadius, r = FastMath.sqrt(inner2
190                + FastMath.nextRandomFloat() * (outer2 - inner2)), theta = FastMath
191                .nextRandomFloat()
192                * FastMath.TWO_PI;
193        up.cross(Vector3f.UNIT_X, b1);
194        if (b1.lengthSquared() < FastMath.FLT_EPSILON) {
195            up.cross(Vector3f.UNIT_Y, b1);
196        }
197        b1.normalizeLocal();
198        up.cross(b1, b2);
199        result.set(b1).multLocal(r * FastMath.cos(theta)).addLocal(center);
200        result.scaleAdd(r * FastMath.sin(theta), b2, result);
201        return result;
202    }
203
204    public void write(JmeExporter e) throws IOException {
205        OutputCapsule capsule = e.getCapsule(this);
206        capsule.write(center, "center", Vector3f.ZERO);
207        capsule.write(up, "up", Vector3f.UNIT_Z);
208        capsule.write(innerRadius, "innerRadius", 0f);
209        capsule.write(outerRadius, "outerRadius", 1f);
210    }
211
212    public void read(JmeImporter e) throws IOException {
213        InputCapsule capsule = e.getCapsule(this);
214        center = (Vector3f) capsule.readSavable("center",
215                Vector3f.ZERO.clone());
216        up = (Vector3f) capsule
217                .readSavable("up", Vector3f.UNIT_Z.clone());
218        innerRadius = capsule.readFloat("innerRadius", 0f);
219        outerRadius = capsule.readFloat("outerRadius", 1f);
220    }
221
222    @Override
223    public Ring clone() {
224        try {
225            Ring r = (Ring) super.clone();
226            r.center = center.clone();
227            r.up = up.clone();
228            return r;
229        } catch (CloneNotSupportedException e) {
230            throw new AssertionError();
231        }
232    }
233}