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.*;
35import com.jme3.util.BufferUtils;
36import com.jme3.util.TempVars;
37import java.io.IOException;
38import java.nio.FloatBuffer;
39
40/**
41 * <code>Line</code> defines a line. Where a line is defined as infinite along
42 * two points. The two points of the line are defined as the origin and direction.
43 *
44 * @author Mark Powell
45 * @author Joshua Slack
46 */
47public class Line implements Savable, Cloneable, java.io.Serializable {
48
49    static final long serialVersionUID = 1;
50
51    private Vector3f origin;
52    private Vector3f direction;
53
54    /**
55     * Constructor instantiates a new <code>Line</code> object. The origin and
56     * direction are set to defaults (0,0,0).
57     *
58     */
59    public Line() {
60        origin = new Vector3f();
61        direction = new Vector3f();
62    }
63
64    /**
65     * Constructor instantiates a new <code>Line</code> object. The origin
66     * and direction are set via the parameters.
67     * @param origin the origin of the line.
68     * @param direction the direction of the line.
69     */
70    public Line(Vector3f origin, Vector3f direction) {
71        this.origin = origin;
72        this.direction = direction;
73    }
74
75    /**
76     *
77     * <code>getOrigin</code> returns the origin of the line.
78     * @return the origin of the line.
79     */
80    public Vector3f getOrigin() {
81        return origin;
82    }
83
84    /**
85     *
86     * <code>setOrigin</code> sets the origin of the line.
87     * @param origin the origin of the line.
88     */
89    public void setOrigin(Vector3f origin) {
90        this.origin = origin;
91    }
92
93    /**
94     *
95     * <code>getDirection</code> returns the direction of the line.
96     * @return the direction of the line.
97     */
98    public Vector3f getDirection() {
99        return direction;
100    }
101
102    /**
103     *
104     * <code>setDirection</code> sets the direction of the line.
105     * @param direction the direction of the line.
106     */
107    public void setDirection(Vector3f direction) {
108        this.direction = direction;
109    }
110
111    public float distanceSquared(Vector3f point) {
112        TempVars vars = TempVars.get();
113
114        Vector3f compVec1 = vars.vect1;
115        Vector3f compVec2 = vars.vect2;
116
117        point.subtract(origin, compVec1);
118        float lineParameter = direction.dot(compVec1);
119        origin.add(direction.mult(lineParameter, compVec2), compVec2);
120        compVec2.subtract(point, compVec1);
121        float len = compVec1.lengthSquared();
122        vars.release();
123        return len;
124    }
125
126    public float distance(Vector3f point) {
127        return FastMath.sqrt(distanceSquared(point));
128    }
129
130    public void orthogonalLineFit(FloatBuffer points) {
131        if (points == null) {
132            return;
133        }
134
135        TempVars vars = TempVars.get();
136
137        Vector3f compVec1 = vars.vect1;
138        Vector3f compVec2 = vars.vect2;
139        Matrix3f compMat1 = vars.tempMat3;
140        Eigen3f compEigen1 = vars.eigen;
141
142        points.rewind();
143
144        // compute average of points
145        int length = points.remaining() / 3;
146
147        BufferUtils.populateFromBuffer(origin, points, 0);
148        for (int i = 1; i < length; i++) {
149            BufferUtils.populateFromBuffer(compVec1, points, i);
150            origin.addLocal(compVec1);
151        }
152
153        origin.multLocal(1f / (float) length);
154
155        // compute sums of products
156        float sumXX = 0.0f, sumXY = 0.0f, sumXZ = 0.0f;
157        float sumYY = 0.0f, sumYZ = 0.0f, sumZZ = 0.0f;
158
159        points.rewind();
160        for (int i = 0; i < length; i++) {
161            BufferUtils.populateFromBuffer(compVec1, points, i);
162            compVec1.subtract(origin, compVec2);
163            sumXX += compVec2.x * compVec2.x;
164            sumXY += compVec2.x * compVec2.y;
165            sumXZ += compVec2.x * compVec2.z;
166            sumYY += compVec2.y * compVec2.y;
167            sumYZ += compVec2.y * compVec2.z;
168            sumZZ += compVec2.z * compVec2.z;
169        }
170
171        //find the smallest eigen vector for the direction vector
172        compMat1.m00 = sumYY + sumZZ;
173        compMat1.m01 = -sumXY;
174        compMat1.m02 = -sumXZ;
175        compMat1.m10 = -sumXY;
176        compMat1.m11 = sumXX + sumZZ;
177        compMat1.m12 = -sumYZ;
178        compMat1.m20 = -sumXZ;
179        compMat1.m21 = -sumYZ;
180        compMat1.m22 = sumXX + sumYY;
181
182        compEigen1.calculateEigen(compMat1);
183        direction = compEigen1.getEigenVector(0);
184
185        vars.release();
186    }
187
188    /**
189     *
190     * <code>random</code> determines a random point along the line.
191     * @return a random point on the line.
192     */
193    public Vector3f random() {
194        return random(null);
195    }
196
197    /**
198     * <code>random</code> determines a random point along the line.
199     *
200     * @param result Vector to store result in
201     * @return a random point on the line.
202     */
203    public Vector3f random(Vector3f result) {
204        if (result == null) {
205            result = new Vector3f();
206        }
207        float rand = (float) Math.random();
208
209        result.x = (origin.x * (1 - rand)) + (direction.x * rand);
210        result.y = (origin.y * (1 - rand)) + (direction.y * rand);
211        result.z = (origin.z * (1 - rand)) + (direction.z * rand);
212
213        return result;
214    }
215
216    public void write(JmeExporter e) throws IOException {
217        OutputCapsule capsule = e.getCapsule(this);
218        capsule.write(origin, "origin", Vector3f.ZERO);
219        capsule.write(direction, "direction", Vector3f.ZERO);
220    }
221
222    public void read(JmeImporter e) throws IOException {
223        InputCapsule capsule = e.getCapsule(this);
224        origin = (Vector3f) capsule.readSavable("origin", Vector3f.ZERO.clone());
225        direction = (Vector3f) capsule.readSavable("direction", Vector3f.ZERO.clone());
226    }
227
228    @Override
229    public Line clone() {
230        try {
231            Line line = (Line) super.clone();
232            line.direction = direction.clone();
233            line.origin = origin.clone();
234            return line;
235        } catch (CloneNotSupportedException e) {
236            throw new AssertionError();
237        }
238    }
239}
240