package medusa.georgios.color_factory;
import java.util.ArrayList;
import medusa.georgios.vecmathpackage.Point3f;
import medusa.georgios.vecmathpackage.Tuple3f;
import medusa.georgios.vecmathpackage.Vector3f;
/**
* Part of SRS 3D, a system for viewing macromolecules (http://srs3d.org)
*
* Copyright (C) 2007-2008
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
/**
* Provides an interpolation mechanism using cubic bezier segments to compose a curve.
* The appropriate segments are not pre-calculated. Instead they are computed on demand.
* Simply plug in a vector of coordinates using setCoordinate( Vector coordinates
* ) . The curve is parameterized from 0 to 1. Provide additional parameters to
* control the curve. The members prePoint and postPoint are
* used for computing C1 continuous transitions between neighboring segments. You can
* explicitly set the initial and final tangent to force the curves tangent at parameter
* 0 and 1. Note that the tangent setting is dominant over the pre- and post-point
* setting.
*
* @author Karsten Klein
*
* @created January 20, 2001
*/
public final class CubicBezierCurve3f extends AbstractCurve3f {
/** Plug-in for a point that is appropriate for extrapolation */
public Tuple3f prePoint = null;
/** Plug-in for a point that is appropriate for extrapolation */
public Tuple3f postPoint = null;
/** Plug-in for a the initial tangent */
public Tuple3f initialTangent = null;
/** Plug-in for a the final tangent */
public Tuple3f finalTangent = null;
/** Scale factor for the tangents computed for C1 continuity */
public float tangentScale = 1.0f / 3;
/** Collection of tangents */
private ArrayList tangents = null;
/** The cached segment */
private CubicBezierSegment3f cachedSegment = null;
/** Cached segment index */
private int cachedSegmentIndex = -1;
/**
* Sets the tangents vector of the cubic bezier curve. Note that the number of
* tangents must be at least the same as the numbers of points provided to the
* curve.
*
* @param tangents The new tangents value.
*/
public void setTangents(ArrayList tangents) {
this.tangents = tangents;
}
/**
* Computes the tangent of the curve at parameter parameter .
*
* @param parameter for the computation.
*
* @return Vector3f - the computed tangent.
*/
public final Vector3f computeTangent(float parameter) {
Vector3f tangent = null;
parameter = updateCachedSegment(parameter);
if (cachedSegment != null) {
tangent = cachedSegment.computeTangent(parameter);
} else {
tangent = new Vector3f(1, 0, 0);
}
return tangent;
}
/**
* Computes the point coordinate of the curve at parameter parameter .
*
* @param parameter for the computation.
*
* @return Point3f - the computed coordinate.
*/
public final Point3f computePoint(float parameter) {
Point3f point = null;
parameter = updateCachedSegment(parameter);
if (cachedSegment != null) {
point = cachedSegment.computePoint(parameter);
} else {
point = new Point3f();
}
return point;
}
/**
* Updates the cached segment according to the specified parameter. This means that
* the cached segment is discarded when it is out of scope and replaced by the
* actual one. If the parameter still maps to the segment no replacement is
* performed.
*
* @param parameter for at least one future computations.
*
* @return float - the given parameter is mapped to the segment
* pararmeter that runs from 0 to 1, too.
*/
private final float updateCachedSegment(float parameter) {
ArrayList coordinates = getCoordinates();
int size = coordinates.size();
if (size > 1) {
int index = mapCurveParameterToSegmentIndex(parameter);
parameter = mapCurveParameterToSegmentParamter(index, parameter);
if (cachedSegment == null) {
cachedSegment = new CubicBezierSegment3f();
cachedSegmentIndex = -1;
}
if (index != cachedSegmentIndex) {
cachedSegment.setNode((Tuple3f) coordinates.get(index), 0);
cachedSegment.setNode((Tuple3f) coordinates.get(index + 1), 3);
Tuple3f prePoint;
Tuple3f postPoint;
// in case of we are in the start or end segment, we supply the
// additional information of the pre and post points.
if (index > 0) {
prePoint = (Tuple3f) coordinates.get(index - 1);
} else {
prePoint = this.prePoint;
}
if (index + 2 < size) {
postPoint = (Tuple3f) coordinates.get(index + 2);
} else {
postPoint = this.postPoint;
}
// compute the interpolation (constrain the pending nodes to the given
// properties of the segment)
cachedSegment.computeInterpolation(prePoint, postPoint,
tangentScale);
if (tangents != null) {
// use the tangents
cachedSegment.setInitialTangent((Tuple3f) tangents.get(
index));
cachedSegment.setFinalTangent((Tuple3f) tangents.get(index +
1));
} else {
// set initial tangent explicitly
if (initialTangent != null && index == 0) {
cachedSegment.setInitialTangent(initialTangent);
}
// set final tangent explicitly
if (finalTangent != null && index == size - 2) {
cachedSegment.setFinalTangent(finalTangent);
}
}
cachedSegmentIndex = index;
}
} else {
cachedSegment = null;
}
return parameter;
}
}
Ads help maintain this website.