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 */
32package com.jme3.math;
33
34import com.jme3.export.JmeExporter;
35import com.jme3.export.JmeImporter;
36import com.jme3.export.Savable;
37import java.io.IOException;
38
39/**
40 * <code>Triangle</code> defines an object for containing triangle information.
41 * The triangle is defined by a collection of three {@link Vector3f}
42 * objects.
43 *
44 * @author Mark Powell
45 * @author Joshua Slack
46 */
47public class Triangle extends AbstractTriangle implements Savable, java.io.Serializable {
48
49    static final long serialVersionUID = 1;
50
51    private Vector3f pointa = new Vector3f();
52    private Vector3f pointb = new Vector3f();
53    private Vector3f pointc = new Vector3f();
54    private transient Vector3f center;
55    private transient Vector3f normal;
56    private float projection;
57    private int index;
58
59    public Triangle() {
60    }
61
62    /**
63     * Constructor instantiates a new <Code>Triangle</code> object with the
64     * supplied vectors as the points. It is recommended that the vertices
65     * be supplied in a counter clockwise winding to support normals for a
66     * right handed coordinate system.
67     * @param p1 the first point of the triangle.
68     * @param p2 the second point of the triangle.
69     * @param p3 the third point of the triangle.
70     */
71    public Triangle(Vector3f p1, Vector3f p2, Vector3f p3) {
72        pointa.set(p1);
73        pointb.set(p2);
74        pointc.set(p3);
75    }
76
77    /**
78     *
79     * <code>get</code> retrieves a point on the triangle denoted by the index
80     * supplied.
81     * @param i the index of the point.
82     * @return the point.
83     */
84    public Vector3f get(int i) {
85        switch (i) {
86            case 0:
87                return pointa;
88            case 1:
89                return pointb;
90            case 2:
91                return pointc;
92            default:
93                return null;
94        }
95    }
96
97    public Vector3f get1() {
98        return pointa;
99    }
100
101    public Vector3f get2() {
102        return pointb;
103    }
104
105    public Vector3f get3() {
106        return pointc;
107    }
108
109    /**
110     *
111     * <code>set</code> sets one of the triangle's points to that specified as
112     * a parameter.
113     * @param i the index to place the point.
114     * @param point the point to set.
115     */
116    public void set(int i, Vector3f point) {
117        switch (i) {
118            case 0:
119                pointa.set(point);
120                break;
121            case 1:
122                pointb.set(point);
123                break;
124            case 2:
125                pointc.set(point);
126                break;
127        }
128    }
129
130    /**
131     *
132     * <code>set</code> sets one of the triangle's points to that specified as
133     * a parameter.
134     * @param i the index to place the point.
135     */
136    public void set(int i, float x, float y, float z) {
137        switch (i) {
138            case 0:
139                pointa.set(x, y, z);
140                break;
141            case 1:
142                pointb.set(x, y, z);
143                break;
144            case 2:
145                pointc.set(x, y, z);
146                break;
147        }
148    }
149
150    public void set1(Vector3f v) {
151        pointa.set(v);
152    }
153
154    public void set2(Vector3f v) {
155        pointb.set(v);
156    }
157
158    public void set3(Vector3f v) {
159        pointc.set(v);
160    }
161
162    public void set(Vector3f v1, Vector3f v2, Vector3f v3) {
163        pointa.set(v1);
164        pointb.set(v2);
165        pointc.set(v3);
166    }
167
168    /**
169     * calculateCenter finds the average point of the triangle.
170     *
171     */
172    public void calculateCenter() {
173        if (center == null) {
174            center = new Vector3f(pointa);
175        } else {
176            center.set(pointa);
177        }
178        center.addLocal(pointb).addLocal(pointc).multLocal(FastMath.ONE_THIRD);
179    }
180
181    /**
182     * calculateNormal generates the normal for this triangle
183     *
184     */
185    public void calculateNormal() {
186        if (normal == null) {
187            normal = new Vector3f(pointb);
188        } else {
189            normal.set(pointb);
190        }
191        normal.subtractLocal(pointa).crossLocal(pointc.x - pointa.x, pointc.y - pointa.y, pointc.z - pointa.z);
192        normal.normalizeLocal();
193    }
194
195    /**
196     * obtains the center point of this triangle (average of the three triangles)
197     * @return the center point.
198     */
199    public Vector3f getCenter() {
200        if (center == null) {
201            calculateCenter();
202        }
203        return center;
204    }
205
206    /**
207     * sets the center point of this triangle (average of the three triangles)
208     * @param center the center point.
209     */
210    public void setCenter(Vector3f center) {
211        this.center = center;
212    }
213
214    /**
215     * obtains the unit length normal vector of this triangle, if set or
216     * calculated
217     *
218     * @return the normal vector
219     */
220    public Vector3f getNormal() {
221        if (normal == null) {
222            calculateNormal();
223        }
224        return normal;
225    }
226
227    /**
228     * sets the normal vector of this triangle (to conform, must be unit length)
229     * @param normal the normal vector.
230     */
231    public void setNormal(Vector3f normal) {
232        this.normal = normal;
233    }
234
235    /**
236     * obtains the projection of the vertices relative to the line origin.
237     * @return the projection of the triangle.
238     */
239    public float getProjection() {
240        return this.projection;
241    }
242
243    /**
244     * sets the projection of the vertices relative to the line origin.
245     * @param projection the projection of the triangle.
246     */
247    public void setProjection(float projection) {
248        this.projection = projection;
249    }
250
251    /**
252     * obtains an index that this triangle represents if it is contained in a OBBTree.
253     * @return the index in an OBBtree
254     */
255    public int getIndex() {
256        return index;
257    }
258
259    /**
260     * sets an index that this triangle represents if it is contained in a OBBTree.
261     * @param index the index in an OBBtree
262     */
263    public void setIndex(int index) {
264        this.index = index;
265    }
266
267    public static Vector3f computeTriangleNormal(Vector3f v1, Vector3f v2, Vector3f v3, Vector3f store) {
268        if (store == null) {
269            store = new Vector3f(v2);
270        } else {
271            store.set(v2);
272        }
273
274        store.subtractLocal(v1).crossLocal(v3.x - v1.x, v3.y - v1.y, v3.z - v1.z);
275        return store.normalizeLocal();
276    }
277
278    public void write(JmeExporter e) throws IOException {
279        e.getCapsule(this).write(pointa, "pointa", Vector3f.ZERO);
280        e.getCapsule(this).write(pointb, "pointb", Vector3f.ZERO);
281        e.getCapsule(this).write(pointc, "pointc", Vector3f.ZERO);
282    }
283
284    public void read(JmeImporter e) throws IOException {
285        pointa = (Vector3f) e.getCapsule(this).readSavable("pointa", Vector3f.ZERO.clone());
286        pointb = (Vector3f) e.getCapsule(this).readSavable("pointb", Vector3f.ZERO.clone());
287        pointc = (Vector3f) e.getCapsule(this).readSavable("pointc", Vector3f.ZERO.clone());
288    }
289
290    @Override
291    public Triangle clone() {
292        try {
293            Triangle t = (Triangle) super.clone();
294            t.pointa = pointa.clone();
295            t.pointb = pointb.clone();
296            t.pointc = pointc.clone();
297            return t;
298        } catch (CloneNotSupportedException e) {
299            throw new AssertionError();
300        }
301    }
302}
303