/* This file is part of the source code for 3D-XplorMath-J, Version 1.0 (January 2008).
* Copyright (c) 2008 The 3D-XplorMath Consortium (http://3d-xplormath.org).
* This source code is released under a BSD License, which allows redistribution
* in source and binary form, with or without modification, provided copyright
* and license information are included, and with no warranty or guarantee of
* any kind. For details, see http://3d-xplormath.org/j/source/BSDLicense.txt
*/
package vmm3d.planecurve.parametric;
import java.awt.Color;
import org.freehep.graphics2d.VectorGraphics;
import java.awt.event.ActionEvent;
import java.awt.geom.Point2D;
import vmm3d.actions.AbstractActionVMM;
import vmm3d.actions.ActionList;
import vmm3d.actions.ToggleAction;
import vmm3d.core.Animation;
import vmm3d.core.Display;
import vmm3d.core.I18n;
import vmm3d.core.IntegerParam;
import vmm3d.core.RealParam;
import vmm3d.core.SaveAndRestore;
import vmm3d.core.TimerAnimation;
import vmm3d.core.Transform;
import vmm3d.core.VMMSave;
import vmm3d.core.View;
import vmm3d.planecurve.PlaneCurve;
/**
* A curve in the plane that is defined by differentiable functions x(t) and y(t).
*/
abstract public class PlaneCurveParametric extends PlaneCurve {
/**
* The number of t-values for points on the curve. Points of the form (x(t),y(t))
* are computed for 1 plus this many values of t, and these points are joined by line segments
* to draw the curve. Note that the starting and ending values of t are given by
* the values of {@link #tmin} and {@link #tmax}. This interval is divided into
* tResolution sub-intervals, giving tResolution+1 points.
*/
protected IntegerParam tResolution;
/**
* The minimum valur of t for points on the curve.
*/
protected RealParam tmin;
/**
* The maximum value of t for points on the curve.
*/
protected RealParam tmax;
/**
* The t-values used to compute the points (x(t),y(t)) on the curve. These are
* evenly spaced between the minimum and maximum t-values.
*/
protected double[] tVals; // input t-values for computing the points on the curve.
/**
* Computes x(t) for a given value of t.
*/
abstract public double xValue(double t);
/**
* Computes y(t) for a given value of t.
*/
abstract public double yValue(double t);
/**
* Computes x'(t) for a given value of t. The default version defined in this class computes an approximate
* value numerically, using values of the function itself at points near t.
*/
public double xDerivativeValue(double t) {
double dx = 0.001; // TODO: decide what value to use here and in second derivative
double f1 = xValue(t + dx);
double f2 = xValue(t + 2*dx);
double g1 = xValue(t - dx);
double g2 = xValue(t - 2*dx);
return ((8 * f1 + g2) - (f2 + 8 * g1))/(12 * dx);
}
/**
* Computes y'(t) for a given value of t. The default version defined in this class computes an approximate
* value numerically, using values of the function itself at points near t.
*/
public double yDerivativeValue(double t) {
double dx = 0.001;
double f1 = yValue(t + dx);
double f2 = yValue(t + 2*dx);
double g1 = yValue(t - dx);
double g2 = yValue(t - 2*dx);
return ((8 * f1 + g2) - (f2 + 8 * g1))/(12 * dx);
}
/**
* Computes x''(t) for a given value of t. The default version defined in this class computes an approximate
* value numerically, using values of the function itself at points near t.
*/
public double x2ndDerivativeValue(double t) {
double dx = 0.001;
double f0 = xValue(t);
double f1 = xValue(t + dx);
double f2 = xValue(t + 2*dx);
double g1 = xValue(t - dx);
double g2 = xValue(t - 2*dx);
return ((16 * f1 + 16 * g1) - 30 * f0 - f2 - g2) / (12 * dx * dx);
}
/**
* Computes y''(t) for a given value of t. The default version defined in this class computes an approximate
* value numerically, using values of the function itself at points near t.
*/
public double y2ndDerivativeValue(double t) {
double dx = 0.001;
double f0 = yValue(t);
double f1 = yValue(t + dx);
double f2 = yValue(t + 2*dx);
double g1 = yValue(t - dx);
double g2 = yValue(t - 2*dx);
return ((16 * f1 + 16 * g1) - 30 * f0 - f2 - g2) / (12 * dx * dx);
}
/**
* Construct a plane curve with Parameters tmin, tmax, and tResolution. The
* curve will be defined by the functions xValue and yValue
* in a concrete subclass.
*/
public PlaneCurveParametric() {
tmin = new RealParam("vmm3d.planecurve.parametric.PlaneCurveParameteric.tmin",-5);
tmax = new RealParam("vmm3d.planecurve.parametric.PlaneCurveParameteric.tmax",5);
tResolution = new IntegerParam("vmm3d.planecurve.parametric.PlaneCurveParameteric.tResolution",100);
tResolution.setMinimumValueForInput(4);
tResolution.setMaximumValueForInput(2000);
addParameter(tResolution);
addParameter(tmax);
addParameter(tmin);
}
/**
* Returns the number of intervals into which the curve is divided. Note that the number
* of points that are drawn on the curve is one more than the tResolution.
*/
public int getTResolution() {
return tResolution.getValue();
}
/**
* Return the t-value for one of the points on the curve. The number of points
* is getTResolution() + 1, and they are numbered from 0 to getTResolution().
* If this method is called before the curve has been
* drawn, the return value will be Double.NaN. The return value is also Double.NaN
* if the specified index is not in the range 0 to getTResolution(), inclusive.
* The corresponding point on the curve can be obtained by calling xValue() and yValue()
* The value returned by this method is only valid after the curve has been drawn;
* if it is called before that time, the return value will be Double.NaN.
* @param index A position in the array of t-values that specifies which t-value shoud
* be returned.
* @see #getTResolution()
* @see #xValue(double)
* @see #yValue(double)
*/
public double getT(int index) {
if (tVals == null || index < 0 || index > tVals.length)
return Double.NaN;
else
return tVals[index];
}
/**
* parametrized circle to draw circle arcs in different colors.
*/
public Point2D[] myCircle(double mx, double my, double rad, int numPoints){
Point2D[] circPts = new Point2D[numPoints+1];
double s = 0.0;
for (int i = 0; i <= numPoints; i++) {
s = i*2*Math.PI/numPoints;
circPts[i] = new Point2D.Double(mx +rad*Math.cos(s),my +rad*Math.sin(s));
}
return circPts;
}
/**
* Calcululates the array of points for this curve using the functions {@link #xValue(double)} and
* {@link #yValue(double)} to compute the points at equally spaced t-values between {@link #tmin} and {@link #tmax}.
* The number of points is one plus the value of {@link #tResolution}.
*/
protected void makePoints() {
int subintervals = tResolution.getValue();
tVals = new double[subintervals+1];
points = new Point2D[subintervals+1];
double t = tmin.getValue();
double dt = (tmax.getValue() - t)/subintervals;
for (int i = 0; i <= subintervals; i++) {
tVals[i] = t + dt*i;
}
for (int i = 0; i <= subintervals; i++) {
double x = xValue(tVals[i]);
double y = yValue(tVals[i]);
if (Double.isNaN(x) || Double.isNaN(y) || Double.isInfinite(x) || Double.isInfinite(y))
points[i] = null;
else
points[i] = new Point2D.Double(x,y);
}
}
/**
* Draw the curve in a specified View. If the View belogs to the nested class
* {@link PlaneCurveParametricView} (which is the default), then only a fraction of the curve
* might be drawn, as specified in the View; this feature is used in the
* creation animation for the curve.
*/
public void doDraw(org.freehep.graphics2d.VectorGraphics g, View view, Transform transform) {
if (points.length == 0)
return;
int pointCt = points.length;
if (view instanceof PlaneCurveParametricView) {
double fraction = ((PlaneCurveParametricView)view).fractionToDraw;
if (fraction >= 0 && fraction < 1)
pointCt = (int)(fraction*pointCt);
if (pointCt == 0)
pointCt = 1;
}
view.drawCurve(points,pointCt);
}
/**
* Returns an animation that shows the curve being drawn bit-by-bit.
* @param view The View where the creation animation will be shown. If this
* is null or if it is not an instance of {@link PlaneCurveParametricView}, then the return
* value is null.
*/
public Animation getCreateAnimation(final View view) {
if (view == null || (! (view instanceof PlaneCurveParametricView)))
return null;
return new TimerAnimation(50,20) { // 50 frames, 20 mulliseconds per frame
protected void drawFrame() {
((PlaneCurveParametricView)view).fractionToDraw = frameNumber/50.0;
forceRedraw();
}
public void animationStarting() {
((PlaneCurveParametricView)view).fractionToDraw = 0;
}
public void animationEnding() {
((PlaneCurveParametricView)view).fractionToDraw = 1;
forceRedraw();
}
};
}
/**
* Returns a new instance of the nested class {@link PlaneCurveParametricView}.
*/
public View getDefaultView() {
View view = new PlaneCurveParametricView();
view.setShowAxes(true);
return view;
}
/**
* Returns a list of actions that can be applied to a PlaneCurveParametric.
* This adds a separator and four actions that run various animations to
* the list obtained from super.getActionsForView(view).
* @param view The view for which the actions should apply. If this is null,
* then no new actions are added to those inherited from the superclass.
*/
public ActionList getActionsForView(final View view) {
ActionList actions = super.getActionsForView(view);
if (view == null)
return actions;
actions.add(null);
double[] window = getDefaultWindow();
final double width = Math.max(Math.abs(window[1] - window[0]), Math.abs(window[3] - window[2]));
actions.add( new AbstractActionVMM(I18n.tr("vmm3d.planecurve.parametric.PlaneCurveParameteric.showParallelCurves")) {
public void actionPerformed(ActionEvent evt) {
Display display = view.getDisplay();
display.installAnimation(new ParallelCurveAnimation(view, PlaneCurveParametric.this, false, width, width/200));
}
});
actions.add( new AbstractActionVMM(I18n.tr("vmm3d.planecurve.parametric.PlaneCurveParameteric.showParallelCurvesWithNormals")) {
public void actionPerformed(ActionEvent evt) {
Display display = view.getDisplay();
display.installAnimation(new ParallelCurveAnimation(view, PlaneCurveParametric.this, true, width, width/200));
}
});
actions.add( new AbstractActionVMM(I18n.tr("vmm3d.planecurve.parametric.PlaneCurveParameteric.showOsculatingCircles")) {
public void actionPerformed(ActionEvent evt) {
Display display = view.getDisplay();
display.installAnimation(new OsculatingCircleAnimation(view, PlaneCurveParametric.this, false, true));
}
});
actions.add( new AbstractActionVMM(I18n.tr("vmm3d.planecurve.parametric.PlaneCurveParameteric.showOsculatingCirclesWithNormals")) {
public void actionPerformed(ActionEvent evt) {
Display display = view.getDisplay();
display.installAnimation(new OsculatingCircleAnimation(view, PlaneCurveParametric.this));
}
});
actions.add( new AbstractActionVMM(I18n.tr("vmm3d.planecurve.parametric.PlaneCurveParameteric.showTangentsAndNormals")) {
public void actionPerformed(ActionEvent evt) {
Display display = view.getDisplay();
display.installAnimation( new TimerAnimation(getTResolution(),40) {
TangentAndNormalDecoration dec = new TangentAndNormalDecoration();
protected void animationEnding() {
view.removeDecoration(dec);
}
protected void animationStarting() {
dec.setCurve(PlaneCurveParametric.this);
view.addDecoration(dec);
}
protected void drawFrame() {
dec.setIndex(getFrameNumber());
}
});
}
});
if (view instanceof PlaneCurveParametricView) {
actions.add(null);
actions.add(((PlaneCurveParametricView)view).showEvoluteAction);
}
return actions;
}
/**
* Defines the default View of a PlaneCurveParametric. The only differences
* between this and the top-level class is that PlaneCurveParametricView is antialiased by default
* and it includes a member variable "fractionToDraw" that tells what fraction
* of the curve should actually be drawn in the view; this feature is only
* used in the creation animation, which shows a sequence of frames in which the
* fractionToDraw is gradually increased.
*
NOTE: This muste be public static so that it can be accessed when an object of this
* type is created by {@link SaveAndRestore} while reading a file.
*/
public static class PlaneCurveParametricView extends View {
@VMMSave private boolean showEvolute;
private ToggleAction showEvoluteAction;
private NormalBundleDecoration evolute; // for displaying the evolute;
double fractionToDraw = -1;
public PlaneCurveParametricView() {
setAntialiased(true);
showEvoluteAction = new ToggleAction(I18n.tr("vmm3d.planecurve.parametric.PlaneCurveParameteric.DisplayEvolute")) {
public void actionPerformed(ActionEvent evt) {
setShowEvolute( getState() );
}
};
}
public boolean getShowEvolute() {
return showEvolute;
}
public void setShowEvolute(boolean showEvolute) {
if (this.showEvolute == showEvolute)
return;
this.showEvolute = showEvolute;
showEvoluteAction.setState(showEvolute);
if (showEvolute) {
evolute = new NormalBundleDecoration();
evolute.setShowEvolute(true);
addDecoration(evolute);
}
else {
removeDecoration(evolute);
evolute = null;
}
forceRedraw();
}
NormalBundleDecoration getEvoluteDecoration() { // for use in ParallelCurveAnimation and OsculatingCircleAnimation
return evolute;
}
}
}
Ads help maintain this website.