• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
33 package com.jme3.math;
34 
35 import com.jme3.export.*;
36 import java.io.IOException;
37 import java.util.logging.Logger;
38 
39 /**
40  * <code>Plane</code> defines a plane where Normal dot (x,y,z) = Constant.
41  * This provides methods for calculating a "distance" of a point from this
42  * plane. The distance is pseudo due to the fact that it can be negative if the
43  * point is on the non-normal side of the plane.
44  *
45  * @author Mark Powell
46  * @author Joshua Slack
47  */
48 public class Plane implements Savable, Cloneable, java.io.Serializable {
49 
50     static final long serialVersionUID = 1;
51 
52     private static final Logger logger = Logger
53             .getLogger(Plane.class.getName());
54 
55     public static enum Side {
56         None,
57         Positive,
58         Negative
59     }
60 
61     /**
62      * Vector normal to the plane.
63      */
64     protected Vector3f normal = new Vector3f();
65 
66     /**
67      * Constant of the plane. See formula in class definition.
68      */
69     protected float constant;
70 
71     /**
72      * Constructor instantiates a new <code>Plane</code> object. This is the
73      * default object and contains a normal of (0,0,0) and a constant of 0.
74      */
Plane()75     public Plane() {
76     }
77 
78     /**
79      * Constructor instantiates a new <code>Plane</code> object. The normal
80      * and constant values are set at creation.
81      *
82      * @param normal
83      *            the normal of the plane.
84      * @param constant
85      *            the constant of the plane.
86      */
Plane(Vector3f normal, float constant)87     public Plane(Vector3f normal, float constant) {
88         if (normal == null) {
89             throw new IllegalArgumentException("normal cannot be null");
90         }
91 
92         this.normal.set(normal);
93         this.constant = constant;
94     }
95 
96     /**
97      * <code>setNormal</code> sets the normal of the plane.
98      *
99      * @param normal
100      *            the new normal of the plane.
101      */
setNormal(Vector3f normal)102     public void setNormal(Vector3f normal) {
103         if (normal == null) {
104             throw new IllegalArgumentException("normal cannot be null");
105         }
106         this.normal.set(normal);
107     }
108 
109     /**
110      * <code>setNormal</code> sets the normal of the plane.
111      *
112      */
setNormal(float x, float y, float z)113     public void setNormal(float x, float y, float z) {
114         this.normal.set(x,y,z);
115     }
116 
117     /**
118      * <code>getNormal</code> retrieves the normal of the plane.
119      *
120      * @return the normal of the plane.
121      */
getNormal()122     public Vector3f getNormal() {
123         return normal;
124     }
125 
126     /**
127      * <code>setConstant</code> sets the constant value that helps define the
128      * plane.
129      *
130      * @param constant
131      *            the new constant value.
132      */
setConstant(float constant)133     public void setConstant(float constant) {
134         this.constant = constant;
135     }
136 
137     /**
138      * <code>getConstant</code> returns the constant of the plane.
139      *
140      * @return the constant of the plane.
141      */
getConstant()142     public float getConstant() {
143         return constant;
144     }
145 
getClosestPoint(Vector3f point, Vector3f store)146     public Vector3f getClosestPoint(Vector3f point, Vector3f store){
147 //        float t = constant - normal.dot(point);
148 //        return store.set(normal).multLocal(t).addLocal(point);
149         float t = (constant - normal.dot(point)) / normal.dot(normal);
150         return store.set(normal).multLocal(t).addLocal(point);
151     }
152 
getClosestPoint(Vector3f point)153     public Vector3f getClosestPoint(Vector3f point){
154         return getClosestPoint(point, new Vector3f());
155     }
156 
reflect(Vector3f point, Vector3f store)157     public Vector3f reflect(Vector3f point, Vector3f store){
158         if (store == null)
159             store = new Vector3f();
160 
161         float d = pseudoDistance(point);
162         store.set(normal).negateLocal().multLocal(d * 2f);
163         store.addLocal(point);
164         return store;
165     }
166 
167     /**
168      * <code>pseudoDistance</code> calculates the distance from this plane to
169      * a provided point. If the point is on the negative side of the plane the
170      * distance returned is negative, otherwise it is positive. If the point is
171      * on the plane, it is zero.
172      *
173      * @param point
174      *            the point to check.
175      * @return the signed distance from the plane to a point.
176      */
pseudoDistance(Vector3f point)177     public float pseudoDistance(Vector3f point) {
178         return normal.dot(point) - constant;
179     }
180 
181     /**
182      * <code>whichSide</code> returns the side at which a point lies on the
183      * plane. The positive values returned are: NEGATIVE_SIDE, POSITIVE_SIDE and
184      * NO_SIDE.
185      *
186      * @param point
187      *            the point to check.
188      * @return the side at which the point lies.
189      */
whichSide(Vector3f point)190     public Side whichSide(Vector3f point) {
191         float dis = pseudoDistance(point);
192         if (dis < 0) {
193             return Side.Negative;
194         } else if (dis > 0) {
195             return Side.Positive;
196         } else {
197             return Side.None;
198         }
199     }
200 
isOnPlane(Vector3f point)201     public boolean isOnPlane(Vector3f point){
202         float dist = pseudoDistance(point);
203         if (dist < FastMath.FLT_EPSILON && dist > -FastMath.FLT_EPSILON)
204             return true;
205         else
206             return false;
207     }
208 
209     /**
210      * Initialize this plane using the three points of the given triangle.
211      *
212      * @param t
213      *            the triangle
214      */
setPlanePoints(AbstractTriangle t)215     public void setPlanePoints(AbstractTriangle t) {
216         setPlanePoints(t.get1(), t.get2(), t.get3());
217     }
218 
219     /**
220      * Initialize this plane using a point of origin and a normal.
221      *
222      * @param origin
223      * @param normal
224      */
setOriginNormal(Vector3f origin, Vector3f normal)225     public void setOriginNormal(Vector3f origin, Vector3f normal){
226         this.normal.set(normal);
227         this.constant = normal.x * origin.x + normal.y * origin.y + normal.z * origin.z;
228     }
229 
230     /**
231      * Initialize the Plane using the given 3 points as coplanar.
232      *
233      * @param v1
234      *            the first point
235      * @param v2
236      *            the second point
237      * @param v3
238      *            the third point
239      */
setPlanePoints(Vector3f v1, Vector3f v2, Vector3f v3)240     public void setPlanePoints(Vector3f v1, Vector3f v2, Vector3f v3) {
241         normal.set(v2).subtractLocal(v1);
242         normal.crossLocal(v3.x - v1.x, v3.y - v1.y, v3.z - v1.z)
243                 .normalizeLocal();
244         constant = normal.dot(v1);
245     }
246 
247     /**
248      * <code>toString</code> returns a string thta represents the string
249      * representation of this plane. It represents the normal as a
250      * <code>Vector3f</code> object, so the format is the following:
251      * com.jme.math.Plane [Normal: org.jme.math.Vector3f [X=XX.XXXX, Y=YY.YYYY,
252      * Z=ZZ.ZZZZ] - Constant: CC.CCCCC]
253      *
254      * @return the string representation of this plane.
255      */
256     @Override
toString()257     public String toString() {
258         return getClass().getSimpleName() + " [Normal: " + normal + " - Constant: "
259                 + constant + "]";
260     }
261 
write(JmeExporter e)262     public void write(JmeExporter e) throws IOException {
263         OutputCapsule capsule = e.getCapsule(this);
264         capsule.write(normal, "normal", Vector3f.ZERO);
265         capsule.write(constant, "constant", 0);
266     }
267 
read(JmeImporter e)268     public void read(JmeImporter e) throws IOException {
269         InputCapsule capsule = e.getCapsule(this);
270         normal = (Vector3f) capsule.readSavable("normal", Vector3f.ZERO.clone());
271         constant = capsule.readFloat("constant", 0);
272     }
273 
274     @Override
clone()275     public Plane clone() {
276         try {
277             Plane p = (Plane) super.clone();
278             p.normal = normal.clone();
279             return p;
280         } catch (CloneNotSupportedException e) {
281             throw new AssertionError();
282         }
283     }
284 }
285