Home | History | Annotate | Download | only in math
      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 package com.jme3.math;
     33 
     34 import com.jme3.export.*;
     35 import com.jme3.util.TempVars;
     36 import java.io.IOException;
     37 
     38 /**
     39  * <p>LineSegment represents a segment in the space. This is a portion of a Line
     40  * that has a limited start and end points.</p>
     41  * <p>A LineSegment is defined by an origin, a direction and an extent (or length).
     42  * Direction should be a normalized vector. It is not internally normalized.</p>
     43  * <p>This class provides methods to calculate distances between LineSegments, Rays and Vectors.
     44  * It is also possible to retrieve both end points of the segment {@link LineSegment#getPositiveEnd(Vector3f)}
     45  * and {@link LineSegment#getNegativeEnd(Vector3f)}. There are also methods to check whether
     46  * a point is within the segment bounds.</p>
     47  *
     48  * @see Ray
     49  * @author Mark Powell
     50  * @author Joshua Slack
     51  */
     52 public class LineSegment implements Cloneable, Savable, java.io.Serializable {
     53 
     54     static final long serialVersionUID = 1;
     55 
     56     private Vector3f origin;
     57     private Vector3f direction;
     58     private float extent;
     59 
     60     public LineSegment() {
     61         origin = new Vector3f();
     62         direction = new Vector3f();
     63     }
     64 
     65     public LineSegment(LineSegment ls) {
     66         this.origin = new Vector3f(ls.getOrigin());
     67         this.direction = new Vector3f(ls.getDirection());
     68         this.extent = ls.getExtent();
     69     }
     70 
     71     /**
     72      * <p>Creates a new LineSegment with the given origin, direction and extent.</p>
     73      * <p>Note that the origin is not one of the ends of the LineSegment, but its center.</p>
     74      */
     75     public LineSegment(Vector3f origin, Vector3f direction, float extent) {
     76         this.origin = origin;
     77         this.direction = direction;
     78         this.extent = extent;
     79     }
     80 
     81     /**
     82      * <p>Creates a new LineSegment with a given origin and end. This constructor will calculate the
     83      * center, the direction and the extent.</p>
     84      */
     85     public LineSegment(Vector3f start, Vector3f end) {
     86         this.origin = new Vector3f(0.5f * (start.x + end.x), 0.5f * (start.y + end.y), 0.5f * (start.z + end.z));
     87         this.direction = end.subtract(start);
     88         this.extent = direction.length() * 0.5f;
     89         direction.normalizeLocal();
     90     }
     91 
     92     public void set(LineSegment ls) {
     93         this.origin = new Vector3f(ls.getOrigin());
     94         this.direction = new Vector3f(ls.getDirection());
     95         this.extent = ls.getExtent();
     96     }
     97 
     98     public float distance(Vector3f point) {
     99         return FastMath.sqrt(distanceSquared(point));
    100     }
    101 
    102     public float distance(LineSegment ls) {
    103         return FastMath.sqrt(distanceSquared(ls));
    104     }
    105 
    106     public float distance(Ray r) {
    107         return FastMath.sqrt(distanceSquared(r));
    108     }
    109 
    110     public float distanceSquared(Vector3f point) {
    111         TempVars vars = TempVars.get();
    112         Vector3f compVec1 = vars.vect1;
    113 
    114         point.subtract(origin, compVec1);
    115         float segmentParameter = direction.dot(compVec1);
    116 
    117         if (-extent < segmentParameter) {
    118             if (segmentParameter < extent) {
    119                 origin.add(direction.mult(segmentParameter, compVec1),
    120                         compVec1);
    121             } else {
    122                 origin.add(direction.mult(extent, compVec1), compVec1);
    123             }
    124         } else {
    125             origin.subtract(direction.mult(extent, compVec1), compVec1);
    126         }
    127 
    128         compVec1.subtractLocal(point);
    129         float len = compVec1.lengthSquared();
    130         vars.release();
    131         return len;
    132     }
    133 
    134     public float distanceSquared(LineSegment test) {
    135         TempVars vars = TempVars.get();
    136         Vector3f compVec1 = vars.vect1;
    137 
    138         origin.subtract(test.getOrigin(), compVec1);
    139         float negativeDirectionDot = -(direction.dot(test.getDirection()));
    140         float diffThisDot = compVec1.dot(direction);
    141         float diffTestDot = -(compVec1.dot(test.getDirection()));
    142         float lengthOfDiff = compVec1.lengthSquared();
    143         vars.release();
    144         float determinant = FastMath.abs(1.0f - negativeDirectionDot
    145                 * negativeDirectionDot);
    146         float s0, s1, squareDistance, extentDeterminant0, extentDeterminant1, tempS0, tempS1;
    147 
    148         if (determinant >= FastMath.FLT_EPSILON) {
    149             // segments are not parallel
    150             s0 = negativeDirectionDot * diffTestDot - diffThisDot;
    151             s1 = negativeDirectionDot * diffThisDot - diffTestDot;
    152             extentDeterminant0 = extent * determinant;
    153             extentDeterminant1 = test.getExtent() * determinant;
    154 
    155             if (s0 >= -extentDeterminant0) {
    156                 if (s0 <= extentDeterminant0) {
    157                     if (s1 >= -extentDeterminant1) {
    158                         if (s1 <= extentDeterminant1) // region 0 (interior)
    159                         {
    160                             // minimum at two interior points of 3D lines
    161                             float inverseDeterminant = ((float) 1.0)
    162                                     / determinant;
    163                             s0 *= inverseDeterminant;
    164                             s1 *= inverseDeterminant;
    165                             squareDistance = s0
    166                                     * (s0 + negativeDirectionDot * s1 + (2.0f) * diffThisDot)
    167                                     + s1
    168                                     * (negativeDirectionDot * s0 + s1 + (2.0f) * diffTestDot)
    169                                     + lengthOfDiff;
    170                         } else // region 3 (side)
    171                         {
    172                             s1 = test.getExtent();
    173                             tempS0 = -(negativeDirectionDot * s1 + diffThisDot);
    174                             if (tempS0 < -extent) {
    175                                 s0 = -extent;
    176                                 squareDistance = s0 * (s0 - (2.0f) * tempS0)
    177                                         + s1 * (s1 + (2.0f) * diffTestDot)
    178                                         + lengthOfDiff;
    179                             } else if (tempS0 <= extent) {
    180                                 s0 = tempS0;
    181                                 squareDistance = -s0 * s0 + s1
    182                                         * (s1 + (2.0f) * diffTestDot)
    183                                         + lengthOfDiff;
    184                             } else {
    185                                 s0 = extent;
    186                                 squareDistance = s0 * (s0 - (2.0f) * tempS0)
    187                                         + s1 * (s1 + (2.0f) * diffTestDot)
    188                                         + lengthOfDiff;
    189                             }
    190                         }
    191                     } else // region 7 (side)
    192                     {
    193                         s1 = -test.getExtent();
    194                         tempS0 = -(negativeDirectionDot * s1 + diffThisDot);
    195                         if (tempS0 < -extent) {
    196                             s0 = -extent;
    197                             squareDistance = s0 * (s0 - (2.0f) * tempS0) + s1
    198                                     * (s1 + (2.0f) * diffTestDot)
    199                                     + lengthOfDiff;
    200                         } else if (tempS0 <= extent) {
    201                             s0 = tempS0;
    202                             squareDistance = -s0 * s0 + s1
    203                                     * (s1 + (2.0f) * diffTestDot)
    204                                     + lengthOfDiff;
    205                         } else {
    206                             s0 = extent;
    207                             squareDistance = s0 * (s0 - (2.0f) * tempS0) + s1
    208                                     * (s1 + (2.0f) * diffTestDot)
    209                                     + lengthOfDiff;
    210                         }
    211                     }
    212                 } else {
    213                     if (s1 >= -extentDeterminant1) {
    214                         if (s1 <= extentDeterminant1) // region 1 (side)
    215                         {
    216                             s0 = extent;
    217                             tempS1 = -(negativeDirectionDot * s0 + diffTestDot);
    218                             if (tempS1 < -test.getExtent()) {
    219                                 s1 = -test.getExtent();
    220                                 squareDistance = s1 * (s1 - (2.0f) * tempS1)
    221                                         + s0 * (s0 + (2.0f) * diffThisDot)
    222                                         + lengthOfDiff;
    223                             } else if (tempS1 <= test.getExtent()) {
    224                                 s1 = tempS1;
    225                                 squareDistance = -s1 * s1 + s0
    226                                         * (s0 + (2.0f) * diffThisDot)
    227                                         + lengthOfDiff;
    228                             } else {
    229                                 s1 = test.getExtent();
    230                                 squareDistance = s1 * (s1 - (2.0f) * tempS1)
    231                                         + s0 * (s0 + (2.0f) * diffThisDot)
    232                                         + lengthOfDiff;
    233                             }
    234                         } else // region 2 (corner)
    235                         {
    236                             s1 = test.getExtent();
    237                             tempS0 = -(negativeDirectionDot * s1 + diffThisDot);
    238                             if (tempS0 < -extent) {
    239                                 s0 = -extent;
    240                                 squareDistance = s0 * (s0 - (2.0f) * tempS0)
    241                                         + s1 * (s1 + (2.0f) * diffTestDot)
    242                                         + lengthOfDiff;
    243                             } else if (tempS0 <= extent) {
    244                                 s0 = tempS0;
    245                                 squareDistance = -s0 * s0 + s1
    246                                         * (s1 + (2.0f) * diffTestDot)
    247                                         + lengthOfDiff;
    248                             } else {
    249                                 s0 = extent;
    250                                 tempS1 = -(negativeDirectionDot * s0 + diffTestDot);
    251                                 if (tempS1 < -test.getExtent()) {
    252                                     s1 = -test.getExtent();
    253                                     squareDistance = s1
    254                                             * (s1 - (2.0f) * tempS1) + s0
    255                                             * (s0 + (2.0f) * diffThisDot)
    256                                             + lengthOfDiff;
    257                                 } else if (tempS1 <= test.getExtent()) {
    258                                     s1 = tempS1;
    259                                     squareDistance = -s1 * s1 + s0
    260                                             * (s0 + (2.0f) * diffThisDot)
    261                                             + lengthOfDiff;
    262                                 } else {
    263                                     s1 = test.getExtent();
    264                                     squareDistance = s1
    265                                             * (s1 - (2.0f) * tempS1) + s0
    266                                             * (s0 + (2.0f) * diffThisDot)
    267                                             + lengthOfDiff;
    268                                 }
    269                             }
    270                         }
    271                     } else // region 8 (corner)
    272                     {
    273                         s1 = -test.getExtent();
    274                         tempS0 = -(negativeDirectionDot * s1 + diffThisDot);
    275                         if (tempS0 < -extent) {
    276                             s0 = -extent;
    277                             squareDistance = s0 * (s0 - (2.0f) * tempS0) + s1
    278                                     * (s1 + (2.0f) * diffTestDot)
    279                                     + lengthOfDiff;
    280                         } else if (tempS0 <= extent) {
    281                             s0 = tempS0;
    282                             squareDistance = -s0 * s0 + s1
    283                                     * (s1 + (2.0f) * diffTestDot)
    284                                     + lengthOfDiff;
    285                         } else {
    286                             s0 = extent;
    287                             tempS1 = -(negativeDirectionDot * s0 + diffTestDot);
    288                             if (tempS1 > test.getExtent()) {
    289                                 s1 = test.getExtent();
    290                                 squareDistance = s1 * (s1 - (2.0f) * tempS1)
    291                                         + s0 * (s0 + (2.0f) * diffThisDot)
    292                                         + lengthOfDiff;
    293                             } else if (tempS1 >= -test.getExtent()) {
    294                                 s1 = tempS1;
    295                                 squareDistance = -s1 * s1 + s0
    296                                         * (s0 + (2.0f) * diffThisDot)
    297                                         + lengthOfDiff;
    298                             } else {
    299                                 s1 = -test.getExtent();
    300                                 squareDistance = s1 * (s1 - (2.0f) * tempS1)
    301                                         + s0 * (s0 + (2.0f) * diffThisDot)
    302                                         + lengthOfDiff;
    303                             }
    304                         }
    305                     }
    306                 }
    307             } else {
    308                 if (s1 >= -extentDeterminant1) {
    309                     if (s1 <= extentDeterminant1) // region 5 (side)
    310                     {
    311                         s0 = -extent;
    312                         tempS1 = -(negativeDirectionDot * s0 + diffTestDot);
    313                         if (tempS1 < -test.getExtent()) {
    314                             s1 = -test.getExtent();
    315                             squareDistance = s1 * (s1 - (2.0f) * tempS1) + s0
    316                                     * (s0 + (2.0f) * diffThisDot)
    317                                     + lengthOfDiff;
    318                         } else if (tempS1 <= test.getExtent()) {
    319                             s1 = tempS1;
    320                             squareDistance = -s1 * s1 + s0
    321                                     * (s0 + (2.0f) * diffThisDot)
    322                                     + lengthOfDiff;
    323                         } else {
    324                             s1 = test.getExtent();
    325                             squareDistance = s1 * (s1 - (2.0f) * tempS1) + s0
    326                                     * (s0 + (2.0f) * diffThisDot)
    327                                     + lengthOfDiff;
    328                         }
    329                     } else // region 4 (corner)
    330                     {
    331                         s1 = test.getExtent();
    332                         tempS0 = -(negativeDirectionDot * s1 + diffThisDot);
    333                         if (tempS0 > extent) {
    334                             s0 = extent;
    335                             squareDistance = s0 * (s0 - (2.0f) * tempS0) + s1
    336                                     * (s1 + (2.0f) * diffTestDot)
    337                                     + lengthOfDiff;
    338                         } else if (tempS0 >= -extent) {
    339                             s0 = tempS0;
    340                             squareDistance = -s0 * s0 + s1
    341                                     * (s1 + (2.0f) * diffTestDot)
    342                                     + lengthOfDiff;
    343                         } else {
    344                             s0 = -extent;
    345                             tempS1 = -(negativeDirectionDot * s0 + diffTestDot);
    346                             if (tempS1 < -test.getExtent()) {
    347                                 s1 = -test.getExtent();
    348                                 squareDistance = s1 * (s1 - (2.0f) * tempS1)
    349                                         + s0 * (s0 + (2.0f) * diffThisDot)
    350                                         + lengthOfDiff;
    351                             } else if (tempS1 <= test.getExtent()) {
    352                                 s1 = tempS1;
    353                                 squareDistance = -s1 * s1 + s0
    354                                         * (s0 + (2.0f) * diffThisDot)
    355                                         + lengthOfDiff;
    356                             } else {
    357                                 s1 = test.getExtent();
    358                                 squareDistance = s1 * (s1 - (2.0f) * tempS1)
    359                                         + s0 * (s0 + (2.0f) * diffThisDot)
    360                                         + lengthOfDiff;
    361                             }
    362                         }
    363                     }
    364                 } else // region 6 (corner)
    365                 {
    366                     s1 = -test.getExtent();
    367                     tempS0 = -(negativeDirectionDot * s1 + diffThisDot);
    368                     if (tempS0 > extent) {
    369                         s0 = extent;
    370                         squareDistance = s0 * (s0 - (2.0f) * tempS0) + s1
    371                                 * (s1 + (2.0f) * diffTestDot) + lengthOfDiff;
    372                     } else if (tempS0 >= -extent) {
    373                         s0 = tempS0;
    374                         squareDistance = -s0 * s0 + s1
    375                                 * (s1 + (2.0f) * diffTestDot) + lengthOfDiff;
    376                     } else {
    377                         s0 = -extent;
    378                         tempS1 = -(negativeDirectionDot * s0 + diffTestDot);
    379                         if (tempS1 < -test.getExtent()) {
    380                             s1 = -test.getExtent();
    381                             squareDistance = s1 * (s1 - (2.0f) * tempS1) + s0
    382                                     * (s0 + (2.0f) * diffThisDot)
    383                                     + lengthOfDiff;
    384                         } else if (tempS1 <= test.getExtent()) {
    385                             s1 = tempS1;
    386                             squareDistance = -s1 * s1 + s0
    387                                     * (s0 + (2.0f) * diffThisDot)
    388                                     + lengthOfDiff;
    389                         } else {
    390                             s1 = test.getExtent();
    391                             squareDistance = s1 * (s1 - (2.0f) * tempS1) + s0
    392                                     * (s0 + (2.0f) * diffThisDot)
    393                                     + lengthOfDiff;
    394                         }
    395                     }
    396                 }
    397             }
    398         } else {
    399             // The segments are parallel. The average b0 term is designed to
    400             // ensure symmetry of the function. That is, dist(seg0,seg1) and
    401             // dist(seg1,seg0) should produce the same number.get
    402             float extentSum = extent + test.getExtent();
    403             float sign = (negativeDirectionDot > 0.0f ? -1.0f : 1.0f);
    404             float averageB0 = (0.5f) * (diffThisDot - sign * diffTestDot);
    405             float lambda = -averageB0;
    406             if (lambda < -extentSum) {
    407                 lambda = -extentSum;
    408             } else if (lambda > extentSum) {
    409                 lambda = extentSum;
    410             }
    411 
    412             squareDistance = lambda * (lambda + (2.0f) * averageB0)
    413                     + lengthOfDiff;
    414         }
    415 
    416         return FastMath.abs(squareDistance);
    417     }
    418 
    419     public float distanceSquared(Ray r) {
    420         Vector3f kDiff = r.getOrigin().subtract(origin);
    421         float fA01 = -r.getDirection().dot(direction);
    422         float fB0 = kDiff.dot(r.getDirection());
    423         float fB1 = -kDiff.dot(direction);
    424         float fC = kDiff.lengthSquared();
    425         float fDet = FastMath.abs(1.0f - fA01 * fA01);
    426         float fS0, fS1, fSqrDist, fExtDet;
    427 
    428         if (fDet >= FastMath.FLT_EPSILON) {
    429             // The ray and segment are not parallel.
    430             fS0 = fA01 * fB1 - fB0;
    431             fS1 = fA01 * fB0 - fB1;
    432             fExtDet = extent * fDet;
    433 
    434             if (fS0 >= (float) 0.0) {
    435                 if (fS1 >= -fExtDet) {
    436                     if (fS1 <= fExtDet) // region 0
    437                     {
    438                         // minimum at interior points of ray and segment
    439                         float fInvDet = ((float) 1.0) / fDet;
    440                         fS0 *= fInvDet;
    441                         fS1 *= fInvDet;
    442                         fSqrDist = fS0
    443                                 * (fS0 + fA01 * fS1 + ((float) 2.0) * fB0)
    444                                 + fS1
    445                                 * (fA01 * fS0 + fS1 + ((float) 2.0) * fB1) + fC;
    446                     } else // region 1
    447                     {
    448                         fS1 = extent;
    449                         fS0 = -(fA01 * fS1 + fB0);
    450                         if (fS0 > (float) 0.0) {
    451                             fSqrDist = -fS0 * fS0 + fS1
    452                                     * (fS1 + ((float) 2.0) * fB1) + fC;
    453                         } else {
    454                             fS0 = (float) 0.0;
    455                             fSqrDist = fS1 * (fS1 + ((float) 2.0) * fB1) + fC;
    456                         }
    457                     }
    458                 } else // region 5
    459                 {
    460                     fS1 = -extent;
    461                     fS0 = -(fA01 * fS1 + fB0);
    462                     if (fS0 > (float) 0.0) {
    463                         fSqrDist = -fS0 * fS0 + fS1
    464                                 * (fS1 + ((float) 2.0) * fB1) + fC;
    465                     } else {
    466                         fS0 = (float) 0.0;
    467                         fSqrDist = fS1 * (fS1 + ((float) 2.0) * fB1) + fC;
    468                     }
    469                 }
    470             } else {
    471                 if (fS1 <= -fExtDet) // region 4
    472                 {
    473                     fS0 = -(-fA01 * extent + fB0);
    474                     if (fS0 > (float) 0.0) {
    475                         fS1 = -extent;
    476                         fSqrDist = -fS0 * fS0 + fS1
    477                                 * (fS1 + ((float) 2.0) * fB1) + fC;
    478                     } else {
    479                         fS0 = (float) 0.0;
    480                         fS1 = -fB1;
    481                         if (fS1 < -extent) {
    482                             fS1 = -extent;
    483                         } else if (fS1 > extent) {
    484                             fS1 = extent;
    485                         }
    486                         fSqrDist = fS1 * (fS1 + ((float) 2.0) * fB1) + fC;
    487                     }
    488                 } else if (fS1 <= fExtDet) // region 3
    489                 {
    490                     fS0 = (float) 0.0;
    491                     fS1 = -fB1;
    492                     if (fS1 < -extent) {
    493                         fS1 = -extent;
    494                     } else if (fS1 > extent) {
    495                         fS1 = extent;
    496                     }
    497                     fSqrDist = fS1 * (fS1 + ((float) 2.0) * fB1) + fC;
    498                 } else // region 2
    499                 {
    500                     fS0 = -(fA01 * extent + fB0);
    501                     if (fS0 > (float) 0.0) {
    502                         fS1 = extent;
    503                         fSqrDist = -fS0 * fS0 + fS1
    504                                 * (fS1 + ((float) 2.0) * fB1) + fC;
    505                     } else {
    506                         fS0 = (float) 0.0;
    507                         fS1 = -fB1;
    508                         if (fS1 < -extent) {
    509                             fS1 = -extent;
    510                         } else if (fS1 > extent) {
    511                             fS1 = extent;
    512                         }
    513                         fSqrDist = fS1 * (fS1 + ((float) 2.0) * fB1) + fC;
    514                     }
    515                 }
    516             }
    517         } else {
    518             // ray and segment are parallel
    519             if (fA01 > (float) 0.0) {
    520                 // opposite direction vectors
    521                 fS1 = -extent;
    522             } else {
    523                 // same direction vectors
    524                 fS1 = extent;
    525             }
    526 
    527             fS0 = -(fA01 * fS1 + fB0);
    528             if (fS0 > (float) 0.0) {
    529                 fSqrDist = -fS0 * fS0 + fS1 * (fS1 + ((float) 2.0) * fB1) + fC;
    530             } else {
    531                 fS0 = (float) 0.0;
    532                 fSqrDist = fS1 * (fS1 + ((float) 2.0) * fB1) + fC;
    533             }
    534         }
    535         return FastMath.abs(fSqrDist);
    536     }
    537 
    538     public Vector3f getDirection() {
    539         return direction;
    540     }
    541 
    542     public void setDirection(Vector3f direction) {
    543         this.direction = direction;
    544     }
    545 
    546     public float getExtent() {
    547         return extent;
    548     }
    549 
    550     public void setExtent(float extent) {
    551         this.extent = extent;
    552     }
    553 
    554     public Vector3f getOrigin() {
    555         return origin;
    556     }
    557 
    558     public void setOrigin(Vector3f origin) {
    559         this.origin = origin;
    560     }
    561 
    562     // P+e*D
    563     public Vector3f getPositiveEnd(Vector3f store) {
    564         if (store == null) {
    565             store = new Vector3f();
    566         }
    567         return origin.add((direction.mult(extent, store)), store);
    568     }
    569 
    570     // P-e*D
    571     public Vector3f getNegativeEnd(Vector3f store) {
    572         if (store == null) {
    573             store = new Vector3f();
    574         }
    575         return origin.subtract((direction.mult(extent, store)), store);
    576     }
    577 
    578     public void write(JmeExporter e) throws IOException {
    579         OutputCapsule capsule = e.getCapsule(this);
    580         capsule.write(origin, "origin", Vector3f.ZERO);
    581         capsule.write(direction, "direction", Vector3f.ZERO);
    582         capsule.write(extent, "extent", 0);
    583     }
    584 
    585     public void read(JmeImporter e) throws IOException {
    586         InputCapsule capsule = e.getCapsule(this);
    587         origin = (Vector3f) capsule.readSavable("origin", Vector3f.ZERO.clone());
    588         direction = (Vector3f) capsule.readSavable("direction", Vector3f.ZERO.clone());
    589         extent = capsule.readFloat("extent", 0);
    590     }
    591 
    592     @Override
    593     public LineSegment clone() {
    594         try {
    595             LineSegment segment = (LineSegment) super.clone();
    596             segment.direction = direction.clone();
    597             segment.origin = origin.clone();
    598             return segment;
    599         } catch (CloneNotSupportedException e) {
    600             throw new AssertionError();
    601         }
    602     }
    603 
    604     /**
    605      * <p>Evaluates whether a given point is contained within the axis aligned bounding box
    606      * that contains this LineSegment.</p><p>This function is float error aware.</p>
    607      */
    608     public boolean isPointInsideBounds(Vector3f point) {
    609         return isPointInsideBounds(point, Float.MIN_VALUE);
    610     }
    611 
    612     /**
    613      * <p>Evaluates whether a given point is contained within the axis aligned bounding box
    614      * that contains this LineSegment.</p><p>This function accepts an error parameter, which
    615      * is added to the extent of the bounding box.</p>
    616      */
    617     public boolean isPointInsideBounds(Vector3f point, float error) {
    618 
    619         if (FastMath.abs(point.x - origin.x) > FastMath.abs(direction.x * extent) + error) {
    620             return false;
    621         }
    622         if (FastMath.abs(point.y - origin.y) > FastMath.abs(direction.y * extent) + error) {
    623             return false;
    624         }
    625         if (FastMath.abs(point.z - origin.z) > FastMath.abs(direction.z * extent) + error) {
    626             return false;
    627         }
    628 
    629         return true;
    630     }
    631 }
    632