All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ardor3d.math.LineSegment3 Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (c) 2008-2012 Ardor Labs, Inc.
 *
 * This file is part of Ardor3D.
 *
 * Ardor3D is free software: you can redistribute it and/or modify it 
 * under the terms of its license which may be found in the accompanying
 * LICENSE file or at .
 */

package com.ardor3d.math;

import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import com.ardor3d.math.type.ReadOnlyLineSegment3;
import com.ardor3d.math.type.ReadOnlyVector3;
import com.ardor3d.util.export.InputCapsule;
import com.ardor3d.util.export.OutputCapsule;

/**
 * LineSegment describes a line with a discrete length with an "origin" in the center, extending in the given
 * "direction" and it's opposite by an "extent" amount.
 */
public class LineSegment3 extends Line3Base implements ReadOnlyLineSegment3, Poolable {

    private static final long serialVersionUID = 1L;

    private static final ObjectPool LINESEG3_POOL = ObjectPool.create(LineSegment3.class,
            MathConstants.maxMathPoolSize);

    protected double _extent;

    /**
     * Constructs a new segment segment with an origin at (0,0,0) a direction of (0,0,1) and an extent of 0.5.
     */
    public LineSegment3() {
        super(Vector3.ZERO, Vector3.UNIT_Z);
        _extent = 0.5;
    }

    /**
     * Copy constructor.
     * 
     * @param source
     *            the line segment to copy from.
     */
    public LineSegment3(final ReadOnlyLineSegment3 source) {
        this(source.getOrigin(), source.getDirection(), source.getExtent());
    }

    /**
     * Constructs a new segment segment using the supplied origin point, unit length direction vector and extent
     * 
     * @param origin
     * @param direction
     *            - unit length
     * @param extent
     */
    public LineSegment3(final ReadOnlyVector3 origin, final ReadOnlyVector3 direction, final double extent) {
        super(origin, direction);
        _extent = extent;
    }

    /**
     * Constructs a new segment segment using the supplied start and end points
     * 
     * @param start
     * @param end
     */
    public LineSegment3(final ReadOnlyVector3 start, final ReadOnlyVector3 end) {
        this();
        _origin.set(start).addLocal(end).multiplyLocal(0.5);
        _direction.set(end).subtractLocal(start);
        _extent = 0.5 * _direction.length();
        _direction.normalizeLocal();
    }

    /**
     * Copies the values of the given source segment into this segment.
     * 
     * @param source
     * @return this segment for chaining
     * @throws NullPointerException
     *             if source is null.
     */
    public LineSegment3 set(final ReadOnlyLineSegment3 source) {
        _origin.set(source.getOrigin());
        _direction.set(source.getDirection());
        return this;
    }

    /**
     * @return this segment's extent value
     */
    @Override
    public double getExtent() {
        return _extent;
    }

    /**
     * Sets the segment's extent to the provided value.
     * 
     * @param extent
     */
    public void setExtent(final double extent) {
        _extent = extent;
    }

    public Vector3 getPositiveEnd(final Vector3 store) {
        Vector3 result = store;
        if (result == null) {
            result = new Vector3();
        }
        result.set(getDirection()).multiplyLocal(_extent);
        result.addLocal(getOrigin());
        return result;
    }

    public Vector3 getNegativeEnd(final Vector3 store) {
        Vector3 result = store;
        if (result == null) {
            result = new Vector3();
        }
        result.set(getDirection()).multiplyLocal(-_extent);
        result.addLocal(getOrigin());
        return result;
    }

    /**
     * @param point
     * @param store
     *            if not null, the closest point is stored in this param
     * @return the squared distance from this segment to the given point.
     * @throws NullPointerException
     *             if the point is null.
     */
    @Override
    public double distanceSquared(final ReadOnlyVector3 point, final Vector3 store) {
        final Vector3 vectorA = Vector3.fetchTempInstance();
        vectorA.set(point).subtractLocal(_origin);

        // Note: assumes direction is normalized
        final double t0 = _direction.dot(vectorA);

        if (-_extent < t0) {
            if (t0 < _extent) {
                // d = |P - (O + t*D)|
                vectorA.set(getDirection()).multiplyLocal(t0);
                vectorA.addLocal(getOrigin());
            } else {
                // ray is closest to positive (end) end point
                getPositiveEnd(vectorA);
            }
        } else {
            // ray is closest to negative (start) end point
            getNegativeEnd(vectorA);
        }

        // Save away the closest point if requested.
        if (store != null) {
            store.set(vectorA);
        }

        point.subtract(vectorA, vectorA);
        final double lSQ = vectorA.lengthSquared();
        Vector3.releaseTempInstance(vectorA);
        return lSQ;
    }

    /**
     * 
     * @param position
     *            a random position lying somewhere on this line segment.
     */
    public Vector3 random(final Vector3 store) {
        Vector3 result = store;
        if (result == null) {
            result = new Vector3();
        }
        final double rand = MathUtils.nextRandomDouble();

        result.setX(2 * _extent * getOrigin().getX() * (1 - rand) + getDirection().getX() * _extent * (2 * rand - 1));
        result.setY(2 * _extent * getOrigin().getY() * (1 - rand) + getDirection().getY() * _extent * (2 * rand - 1));
        result.setZ(2 * _extent * getOrigin().getZ() * (1 - rand) + getDirection().getZ() * _extent * (2 * rand - 1));

        return result;
    }

    /**
     * Check a segment... if it is null or the values of its origin or direction or extent are NaN or infinite, return
     * false. Else return true.
     * 
     * @param segment
     *            the segment to check
     * @return true or false as stated above.
     */
    public static boolean isValid(final ReadOnlyLineSegment3 segment) {
        if (segment == null) {
            return false;
        }

        return Vector3.isValid(segment.getDirection()) && Vector3.isValid(segment.getOrigin())
                && !Double.isInfinite(segment.getExtent()) && !Double.isNaN(segment.getExtent());
    }

    /**
     * @return the string representation of this segment.
     */
    @Override
    public String toString() {
        return "com.ardor3d.math.LineSegment3 [Origin: " + _origin + " - Direction: " + _direction + " - Extent: "
                + _extent + "]";
    }

    /**
     * @param o
     *            the object to compare for equality
     * @return true if this segment and the provided segment have the same constant and normal values.
     */
    @Override
    public boolean equals(final Object o) {
        if (this == o) {
            return true;
        }
        if (!(o instanceof ReadOnlyLineSegment3)) {
            return false;
        }
        final ReadOnlyLineSegment3 comp = (ReadOnlyLineSegment3) o;
        return _origin.equals(comp.getOrigin()) && _direction.equals(comp.getDirection())
                && _extent == comp.getExtent();
    }

    /**
     * @return returns a unique code for this segment object based on its values.
     */
    @Override
    public int hashCode() {
        int result = 17;

        result += 31 * result + _origin.hashCode();
        result += 31 * result + _direction.hashCode();
        final long ex = Double.doubleToLongBits(_extent);
        result += 31 * result + (int) (ex ^ ex >>> 32);

        return result;
    }

    // /////////////////
    // Method for Cloneable
    // /////////////////

    @Override
    public LineSegment3 clone() {
        return new LineSegment3(this);
    }

    // /////////////////
    // Methods for Savable
    // /////////////////

    @Override
    public void write(final OutputCapsule capsule) throws IOException {
        super.write(capsule);
        capsule.write(_extent, "extent", 0.0);
    }

    @Override
    public void read(final InputCapsule capsule) throws IOException {
        super.read(capsule);
        _extent = capsule.readDouble("extent", 0.0);
    }

    // /////////////////
    // Methods for Externalizable
    // /////////////////

    /**
     * Used with serialization. Not to be called manually.
     * 
     * @param in
     *            ObjectInput
     * @throws IOException
     * @throws ClassNotFoundException
     */
    @Override
    public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
        super.readExternal(in);
        _extent = in.readDouble();
    }

    /**
     * Used with serialization. Not to be called manually.
     * 
     * @param out
     *            ObjectOutput
     * @throws IOException
     */
    @Override
    public void writeExternal(final ObjectOutput out) throws IOException {
        super.writeExternal(out);
        out.writeDouble(_extent);
    }

    // /////////////////
    // Methods for creating temp variables (pooling)
    // /////////////////

    /**
     * @return An instance of LineSegment3 that is intended for temporary use in calculations and so forth. Multiple
     *         calls to the method should return instances of this class that are not currently in use.
     */
    public final static LineSegment3 fetchTempInstance() {
        if (MathConstants.useMathPools) {
            return LineSegment3.LINESEG3_POOL.fetch();
        } else {
            return new LineSegment3();
        }
    }

    /**
     * Releases a LineSegment3 back to be used by a future call to fetchTempInstance. TAKE CARE: this LineSegment3
     * object should no longer have other classes referencing it or "Bad Things" will happen.
     * 
     * @param segment
     *            the LineSegment3 to release.
     */
    public final static void releaseTempInstance(final LineSegment3 segment) {
        if (MathConstants.useMathPools) {
            LineSegment3.LINESEG3_POOL.release(segment);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy