the ParametricPath to represent with a numerical table
Optional opt_tableLength: numberoptional number of points to store in table; default is 9000.
Private boundsbounds of the path, in simulation coordinates
Private dxvalsdx/dp
Private dyvalsdy/dp
Private endend point is used for linear extension, see map_p_to_slope
Private nxnormal x at mid-point
Private nxpderivative of normal w.r.t. p at mid-point
Private nynormal y at mid-point
Private nypderivative of normal w.r.t. p at mid-point
Private plentotal length of path
p, path distance. Is public only because of PointsIterator.
Private startstart point is used for linear extension, see map_p_to_slope
Private Readonly tableNumber of points stored in table.
x, horizontal position. Is public only because of PointsIterator.
y, vertical position. Is public only because of PointsIterator.
Static Readonly DATA_Number of data points to record for the path.
Static IDCounter used for naming SimObjects.
Private deriv3Calculates the three point numerical derivative with respect to path distance,
p. This numerical derivative can handle having the p values
being unevenly spaced.
The three points used to calculate the derivative are:
(pvals[k], yy[k])
(pvals[k+1], yy[k+1])
(pvals[k+2], yy[k+2])
The derivative can be calculated to correspond to the derivative of any of those three points. These are called the left, center, and right derivatives respectively. Usually the center derivative is used, but at table endpoints we need to use the left or right derivative. For example, to get the derivative at the first point in the table, use the left derivative. To get the derivative at the last point in the table, use the right derivative.
See equation 4.3, page 171, of Numerical Analysis, 6th edition by Burden, Faires in section 4.1 Numerical Differentiation for the three-point differentiation formula used here.
the index into the table for the first point of the derivative
selects left, center, or right derivative as j = 0, 1, or 2
three-point derivative of array yy
Private distanceReturns the distance-squared between the given point and a point on the path.
the point of interest
index of point on the path
distance-squared between the given point and a point on the path
Private distanceReturns the distance-squared between the given point and an interpolated point on the path.
the point of interest
path position
index to start search at
distance-squared between the given point and an interpolated point on the path.
Finds the closest point in the path table to the given x,y position in point.
This is a global search for the closest point over the entire path. This does not
interpolate between table entries, see findNearestLocal for a
more accurate mapping using interpolation.
the x,y position to search for
a PathPoint with the x, y, p, and idx fields are set to the
closest point in the table.
Finds the closest point on the interpolated path to the target position, starting
from a given index into the table. This is a local search around the current position
in the path, NOT a global search over the entire path for the very closest point. See
findNearestGlobal. The algorithm used here moves from the starting point in the
direction that reduces the distance between target and the path, until the distance is
at a minimum. This behavior is useful so that the current path point does not “hop”
across to other parts of the path when a path crosses itself.
Preserves the p-value (distance along the path) in the PathPoint for closed
loop paths when crossing the “stitch” point where the loop reconnects. Therefore the
p-value can be any value, not just from 0 to length of path. This is done to simplify
the detection of collisions by for example PhysicsPathAction. Note that this feature
will fail if the point is moving very rapidly around the path.
Outline of the algorithm:
We seek the p that gives minimum y value.
d = initial spacing between p values
p = initial p value
do {
y0 = y(p-d); y1 = y(p); y2 = y(p+d)
if (y0 < y1) {
p = p - d; // shift 'left'
} else if (y2 < y1) {
p = p + d; // shift 'right'
} else {
d = d/2; // reduce search range
}
} while (d > tiny);
the point of interest
the PathPoint used for input and output;
the table index ppt.idx is used to start the search;
the p value and table index are stored in ppt.
Finds point p2 on the path that is a given distance from given point p1. We start the search by finding the point on the path nearest to given point p2. The initial location of p2 determines which side of the path of p1 we find p2 on.
a point on on the path that is distance x from p1.
Returns a rectangle that contains this SimObject in world coordinates.
rectangle that contains this SimObject in world coordinates
Returns the expiration time, when this SimObject should be removed from the SimList. This is intended for temporary SimObjects that illustrate, for example, contact forces or collisions.
the expiration time, in time frame of the Simulation clock
Returns an iterator over points in the Path.
desired number of points
an iterator over points in the Path.
Total path length of this NumericalPath; equal to getFinishPValue minus getStartPValue.
total path length of this NumericalPath from start to finish
Name of this SimObject, either the language-independent name for scripting purposes or the localized name for display to user.
The language-independent name should be the same as the English version but capitalized and with spaces and dashes replaced by underscore, see Util.toName, nameEquals.
The name should give an idea of the role of the SimObject in the simulation. This allows us to to treat an object in a special way depending on its name. For example, we might use the name to decide what type of DisplayObject to create to represent the SimObject.
Optional opt_localized: booleantrue means return the localized version of the name;
default is false which means return the language independent name.
name of this SimObject
Whether this implements the MassObject interface.
Whether this implements the MassObject interface.
Returns a p value that is in the range of the path. For a path that is not a
closed loop, this returns start or end of the path when the p value is outside of the
path range. For closed loops this returns path distance p modulo the total path
length, see mod_p.
distance along the path
the equivalent path distance p position, limited to be within the
path.
Private linearFinds the table index corresponding to the given path distance p value, by doing a
linear search. In theory, this is faster than binarySearch when the index is close to
the p value.
TO DO test if we actually save operations using linear search
the p-value to search for in the table
the index into the table to start searching at
index j into table such that pvals[j] <= p < pvals[j+1]
Private make_Makes the table of path data.
TO DO for closed loop we can use the regular centered three-point formula!
Returns the index in the path table just before the given p value. Usually
the returned index point is at or just before the given p value. However if the p
value is before the first entry then this returns index of 0.
More precisely stated: returns largest index k in table such that pvals[k] <= p, or
returns 0 if p < pvals[0].
path value to search for
index in the path table just before the given p value
Given a path location p, calculates all the corresponding PathPoint fields such
as (x,y) location, slope, derivative of (x,y) with respect to p, normal,
derivative of normal, etc. The desired path location is specified in PathPoint.p.
Optionally calculates the radius of curvature if PathPoint.radius_flag is set.
For a non-closed loop path: when the p value is before the start of the path, or
after the end of the path, we use a linear extension of the path to find the point.
Interpolates values in the table to find corresponding values of location, slope, etc.
TO DO Use the new dxdp and dydp fields to calc radius. Find radius of curvature for the four points on circle where tangent is horizontal or vertical. Currently we get radius is infinite there which is wrong.
the PathPoint used for input and output;
PathPoint.p is the input path position. Optionally calculates
the radius of curvature if PathPoint.radius_flag is set.
Uses the x value of the PathPoint to find a point on the path, then
interpolates to find corresponding y and p values.
the PathPoint used for input and output;
ppt.x is the input x value searched for; ppt.y and ppt.p are set
accordingly.
if x values are not monotonically increasing or decreasing
Returns path distance p modulo total path length for closed loops. For paths that
are not closed, this has no effect: it returns the given p value even when it is
outside of the range of the path.
For example, consider a circle of radius 1; its total path length is 2*pi and the
path starts with p at zero. Then mod_p(2*pi + 1) returns 1, but mod_p(pi)
returns pi.
distance along the path
the equivalent path distance p position, modulo total path length for
closed paths
Private modkWhether this SimObject has the given name, adjusting for transformation to the language-independent form of the name, as is done by Util.toName.
the English or language-independent version of the name
whether this SimObject has the given name (adjusted to language-independent form)
Private printPrivate printSets the expiration time, when this SimObject should be removed from the SimList. This is intended for temporary SimObjects that illustrate, for example, contact forces or collisions.
the expiration time, in time frame of the Simulation clock
Returns true if the given SimObject is similar to this SimObject for display purposes. SimObjects are similar when they are the same type and nearly the same size and location. Mainly used when showing forces - to avoid adding too many objects to the display. See SimList.getSimilar.
the SimObject to compare to
Optional _opt_tolerance: numberthe amount the object components can differ by
true if this SimObject is similar to obj for display purposes
Private tableReturns a minimal string representation of this object, usually giving just identity information like the class name and name of the object.
For an object whose main purpose is to represent another Printable object, it is
recommended to include the result of calling toStringShort on that other object.
For example, calling toStringShort() on a DisplayShape might return something like
this:
DisplayShape{polygon:Polygon{'chain3'}}
a minimal string representation of this object.
Static Private binaryFinds where in the array the given value is located using a binary search algorithm.
Given an array arr[0..n-1], and given a value x, binarySearch returns a value i
such that arr[i] <= x and x < arr[i+1]. The array must be monotonic, either
increasing or decreasing.
TO DO should this return 0 or n-1 when x is outside the array?
the array of values, must be monotonic increasing or decreasing
the value to find
index of the closest value in the table that is less than or equal to x, or -1 or n is returned to indicate that x is out of range.
Static Private interp4Returns the y-value corresponding to the x-value in the 4 point (3rd order)
polynomial interpolant formed from the 4 values in xx and yy
arrays at indexes k, k+1, k+2, k+3. The four points used for
interpolation are therefore
(xx[k], yy[k])
(xx[k+1], yy[k+1])
(xx[k+2], yy[k+2])
(xx[k+3], yy[k+3])
See Introduction to Scientific Computing by Charles F. Van Loan, chapter 2 Polynomial Interpolation p. 77.
Let our three datapoints be (x1,y1), (x2,y2), (x3,y3), (x4,y4)
Our polynomial will be
p(x) = a1 + a2(x-x1) + a3(x-x1)(x-x2) + a4(x-x1)(x-x2)(x-x3)
The first derivative is
p'(x) = a2 + a3(2x-x1-x2) + a4((x-x2)(x-x3) + (x-x1)(2x-x2-x3))
The coefficients are given by solving the system:
a1 = y1
a1 + a2(x2-x1) = y2
a1 + a2(x3-x1) + a3(x3-x1)(x3-x2) = y3
a1 + a2(x4-x1) + a3(x4-x1)(x4-x2) + a4(x4-x1)(x4-x2)(x4-x3) = y4
Solving this system gives:
a1 = y1
a2 = (y2-y1)/(x2-x1)
a3 = (y3 - y1 - a2(x3-x1))/((x3-x2)(x3-x1))
a4 = (y4 - y1 - a2(x4-x1) - a3(x4-x1)(x4-x2))/((x4-x1)(x4-x2)(x4-x3))
array of x-values
array of y-values
the x value for which we want to find the corresponding y-value
the index into the arrays where to get the 4 array values
true when the array wraps around at the end points
the interpolated y-value corresponding to the requested x-value
Static Private isGenerated using TypeDoc
A numerical approximation of a ParametricPath providing various functions to find points based on distance along the path and also the slope, normal, and derivatives at those points. Stores a representation of the ParametricPath as a table of values; interpolation is used to find values between table entries.
Many of the NumericalPath methods pass information via a PathPoint for both input and output.
See the myPhysicsLab page showing the Roller Coaster for more about the math involved here.
Path Length 'p'
Points on the path are usually specified by the path distance to that point from a designated starting point on the path. The starting point is specified by the parametric t-value given by ParametricPath.getStartTValue. At that point the path distance is zero.
Path distance is abbreviated here as
p, so you see methods named like map_p_to_slope which finds the slope at a point specified by thepvalue of the point.Table of Numerical Values
The path is specified by the parametric function
f(t) = (x(t), y(t))which is defined by the ParametricPath provided to the constructor. We build the table by varying the parametertfromtLowtotHighwhich are given by the ParametricPath methods ParametricPath.getStartTValue and ParametricPath.getFinishTValue. The table stores information about each sample point such aspx,yin spacex,ywith respect toppAfter the table is created, the parametric function
f(t)andtLow,tHighare no longer used, instead we interpolate data from the table as needed.Most of the NumericalPath functions start with the
pvalue to specify the point, and the other values are interpolated accordingly.Some functions result in finding a
pvalue from a location in space. For example, when the user clicks the mouse somewhere we need to find the nearest point on the path. See findNearestLocal and findNearestGlobal.Slope of Path
The slope is found from the relation
dy/dx = (dy/dp) / (dx/dp). Because we store these derivatives ofxandywith respect topin the table, we can interpolate those at a given point and divide them to get the slope there.The method map_p_to_slope figures out the slope in this way, and stores it in the
slopeproperty of the PathPoint.Direction of Path
Sometimes it is important to know the direction of the path: i.e. as
pincreases, doesxincrease or decrease? This is determined from the table data as needed. For vertical sections, the question becomes whether aspincreases, doesyincrease or decrease.The method map_p_to_slope figures out the direction in this way, and stores it in the
directionproperty of the PathPoint.Design Note: How Not To Calculate Slope
A previous version stored the slope,
dy/dx, at each point in the table. It turns out to be difficult-to-impossible to interpolate on slope numbers. The slope goes to infinity on vertical sections. You can get around that by interpolating on reciprocal of slope. But a persistent problem is that you can run into situations which are not appropriate for interpolation with a cubic polynomial (which we do with the private static methodNumericalPath.interp4).For example, consider the following case with four values evenly spaced horizontally, but where the
yvalues are highly variable:The
yvalues represent slope and are monotonically increasing. But a cubic polynomial fitted to those points will swing wildly between the first 3 points giving a non-monotonic function that crosses over to negative values.The solution is to not store slope directly, instead store
dy/dpanddx/dpseparately and get the slope at any point from their ratio. Both of those seem to be compatible with polynomial interpolation.TO DO Use a curve to estimate the path distance when making the table.
TO DO PointsIterator should be able to iterate over entire table. That is, parameterize it so that you can say how many sample points you want (less for drawing).
TO DO Provide methods to return copy of the entire table as an array (or the columns).
TO DO ??? Should we always have p increase in the pvals array? This would make the code simpler. And I can't think of any reason to allow pvals to decrease.
TO DO NumericalPath doing makeTable inside of constructor: this is bad because you can’t do something as simple as pass radius to Circle constructor. Also, might want to adjust path later on (translate for example, or scale or rotate). So might want to have the makeTable thing be callable anytime.