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 thep
value 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 parametert
fromtLow
totHigh
which are given by the ParametricPath methods ParametricPath.getStartTValue and ParametricPath.getFinishTValue. The table stores information about each sample point such asp
x,y
in spacex,y
with respect top
p
After the table is created, the parametric function
f(t)
andtLow
,tHigh
are no longer used, instead we interpolate data from the table as needed.Most of the NumericalPath functions start with the
p
value to specify the point, and the other values are interpolated accordingly.Some functions result in finding a
p
value 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 ofx
andy
with respect top
in 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
slope
property of the PathPoint.Direction of Path
Sometimes it is important to know the direction of the path: i.e. as
p
increases, doesx
increase or decrease? This is determined from the table data as needed. For vertical sections, the question becomes whether asp
increases, doesy
increase or decrease.The method map_p_to_slope figures out the direction in this way, and stores it in the
direction
property 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
y
values are highly variable:The
y
values 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/dp
anddx/dp
separately 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.