public abstract class Vector extends DefinitionalObject implements IServiceProvider
This example shows how to create a new Vector class.
// Create a new type derived from Vector. This type will represent an inverted form
// of another vector.
public static class InvertedVector extends Vector {
public InvertedVector() {}
public InvertedVector(Vector vectorToInvert) {
m_vectorToInvert = vectorToInvert;
}
// The copy constructor, used to make a copy of the object. Copy all of the
// fields of the 'existingInstance' to the new object. Reference types should
// be passed through a call to updateReference so that the depth of the copy
// can be controlled by the user. See the documentation of the ICloneWithContext
// interface for more information.
protected InvertedVector(InvertedVector existingInstance, CopyContext context) {
super(existingInstance, context);
m_vectorToInvert = context.updateReference(existingInstance.m_vectorToInvert);
}
// This is called to make a copy of the object, which it does by calling the
// copy constructor above.
@Override
public Object clone(CopyContext context) {
return new InvertedVector(this, context);
}
// This method is only called by the isSameDefinition method in the base class to
// determine if two vectors are equivalent. Derived classes MUST override this method and
// check all new fields introduced by the derived class for definitional equivalence. It
// is NOT necessary to check base class fields because the base class will already have
// done that.
@Override
protected final boolean checkForSameDefinition(Vector other) {
InvertedVector o = (other instanceof InvertedVector) ? (InvertedVector) other : null;
return o != null &&
areSameDefinition(m_vectorToInvert, o.m_vectorToInvert);
}
// Called to determine a hash code for the current configuration of this object.
// Derived classes MUST override this method and compute a hash code that combines:
// a unique hash code seed, the base implementation result, and the
// hash codes of all new fields introduced by the derived class which are used
// in the checkForSameDefinition method.
@Override
protected int computeCurrentDefinitionHashCode() {
return HashCode.combine(InvertedVector.class.hashCode(),
super.computeCurrentDefinitionHashCode(),
getDefinitionHashCode(m_vectorToInvert));
}
// Called to enumerate all of the other objects on which this object depends. This
// allows clients to navigate the graph of objects related to a computation.
@Override
public void enumerateDependencies(DependencyEnumerator enumerator) {
super.enumerateDependencies(enumerator);
enumerator.enumerate(m_vectorToInvert);
}
// The vector to be inverted
public final Vector getVectorToInvert() {
return m_vectorToInvert;
}
// The vector to be inverted
public final void setVectorToInvert(Vector value) {
m_vectorToInvert = value;
}
// This method is responsible for returning an instance of the private
// Evaluator class. It should ensure that the properties are not null or
// in an invalid state, and then use the evaluator group when it constructs
// and returns an instance of the Evaluator.
@Override
public VectorEvaluator getEvaluator(EvaluatorGroup group) {
if (group == null) {
throw new ArgumentNullException("group");
}
// Ensure that the properties are not null.
if (getVectorToInvert() == null) {
throw new PropertyInvalidException("VectorToInvert", PropertyInvalidException.PropertyCannotBeNull);
}
return group.createEvaluator(getEvaluatorCallback);
}
// This method will only be called if the evaluator does not
// yet exist in the group and needs to be created.
private final VectorEvaluator createEvaluator(EvaluatorGroup group) {
// In order to invert the vector, we first must evaluate it.
// Get the evaluator that will allow us to do so.
// Notice that we create this evaluator in the same EvaluatorGroup.
VectorEvaluator vectorEvaluator = getVectorToInvert().getEvaluator(group);
return new Evaluator(group, vectorEvaluator);
}
private final EvaluatorGroup.Callback0<VectorEvaluator> getEvaluatorCallback = EvaluatorGroup.Callback0.of(this::createEvaluator);
private Vector m_vectorToInvert;
// This is the definition of the Evaluator that is used to actually evaluate this Vector.
// Because it is a private, nested class, it is not visible outside of the InvertedVector class.
// This is ok, though, because once it is created users only interact with it via a reference
// to its base class: VectorEvaluator.
private static final class Evaluator extends VectorEvaluator {
// An evaluator should not store any data that the user will be able to change
// after creating the evaluator. This sometimes requires that data required by the
// evaluator be copied or frozen using the IFreezable interface.
public Evaluator(EvaluatorGroup group, VectorEvaluator vectorEvaluator) {
super(group);
m_vectorEvaluator = vectorEvaluator;
}
// The Evaluator's copy constructor will be called from the Clone method.
// Don't forget to call the base class implementation!
private Evaluator(Evaluator existingInstance, CopyContext context) {
super(existingInstance, context);
// For non-evaluator reference types, we would use context.updateReference to
// allow the context to update the references we hold.
// This evaluator does not have any non-evaluator reference fields.
// For evaluators, just assign the reference directly - we'll call updateReference later.
m_vectorEvaluator = existingInstance.m_vectorEvaluator;
// Always call UpdateEvaluatorReferences at the end of the copy constructor.
// This is where references to evaluators will be updated.
updateEvaluatorReferences(context);
}
// This method is used by the EvaluatorGroup system to avoid redundant evaluations. The
// EvaluatorGroup may call it on your evaluator in order to replace your evaluator's
// reference to another evaluator with a reference to a version that caches its last
// result.
@Override
public void updateEvaluatorReferences(CopyContext context) {
m_vectorEvaluator = context.updateReference(m_vectorEvaluator);
}
// The clone method should call the copy constructor.
@Override
public Object clone(CopyContext context) {
return new Evaluator(this, context);
}
// This method determines if there is data available from this Evaluator at
// the specified date.
@Override
public boolean isAvailable(JulianDate date) {
// This evaluator is available whenever the nested evaluator is available.
return m_vectorEvaluator.isAvailable(date);
}
// This method returns a collection of time intervals when data is
// available from this Evaluator.
@Override
public TimeIntervalCollection getAvailabilityIntervals(TimeIntervalCollection consideredIntervals) {
// This evaluator is available whenever the nested evaluator is available.
return m_vectorEvaluator.getAvailabilityIntervals(consideredIntervals);
}
// This property determines if this Evaluator can safely be used from multiple threads
// simultaneously. If the evaluator stores data during the evaluate call, it is not thread
// safe. Otherwise, it generally is thread safe as long as any nested evaluators it uses
// are thread safe.
@Override
public boolean getIsThreadSafe() {
// This evaluator is thread safe as long as the nested evaluator is thread safe.
return m_vectorEvaluator.getIsThreadSafe();
}
// This property determines if this Evaluator result changes depending on the time at which it is evaluated.
@Override
public boolean getIsTimeVarying() {
return m_vectorEvaluator.getIsTimeVarying();
}
// This property expresses the Axes that this Vector is defined in
// for various intervals.
@Override
public TimeIntervalCollection1<Axes> getDefinedInIntervals() {
// This point is defined in the same axes that the nested evaluator is defined in.
return m_vectorEvaluator.getDefinedInIntervals();
}
// This is where we do the actual evaluation when only the value of the vector (not additional derivatives)
// is required.
@Override
public Cartesian evaluate(JulianDate date) {
Cartesian value = m_vectorEvaluator.evaluate(date);
return value.invert();
}
// This is where we do the actual evaluation when additional derivatives of the vector
// are requested as well.
@Override
public Motion1<Cartesian> evaluate(JulianDate date, int order) {
Motion1<Cartesian> motion = m_vectorEvaluator.evaluate(date, order);
// Note that the motion returned from the evaluator may not have all of the
// derivatives that were requested.
Cartesian[] result = new Cartesian[motion.getOrder() + 1];
for (int i = 0; i <= motion.getOrder(); ++i) {
result[i] = motion.get(i).invert();
}
return new Motion1<>(result);
}
// Override the dispose method to call the dispose() method on any nested
// evaluators or other disposable nested types.
@Override
protected void dispose(boolean disposing) {
if (disposing) {
m_vectorEvaluator.dispose();
}
}
private VectorEvaluator m_vectorEvaluator;
}
}
// #region CreateNewScalarType
// Create a new type derived from Scalar. This type will represent the square root of
// another scalar.
public static class SquareRootScalar extends Scalar {
public SquareRootScalar() {}
public SquareRootScalar(Scalar scalarToTakeSquareRootOf) {
m_scalar = scalarToTakeSquareRootOf;
}
// The copy constructor, used to make a copy of the object. Copy all of the
// fields of the 'existingInstance' to the new object. Reference types should
// be passed through a call to updateReference so that the depth of the copy
// can be controlled by the user. See the documentation of the ICloneWithContext
// interface for more information.
protected SquareRootScalar(SquareRootScalar existingInstance, CopyContext context) {
super(existingInstance, context);
m_scalar = context.updateReference(existingInstance.m_scalar);
}
// This is called to make a copy of the object, which it does by calling the
// copy constructor above.
@Override
public Object clone(CopyContext context) {
return new SquareRootScalar(this, context);
}
// This method is only called by the isSameDefinition method in the base class to
// determine if two scalars are equivalent. Derived classes MUST override this method and
// check all new fields introduced by the derived class for definitional equivalence. It
// is NOT necessary to check base class fields because the base class will already have
// done that.
@Override
protected final boolean checkForSameDefinition(Scalar other) {
SquareRootScalar o = (other instanceof SquareRootScalar) ? (SquareRootScalar) other : null;
return o != null &&
areSameDefinition(m_scalar, o.m_scalar);
}
// Called to determine a hash code for the current configuration of this object.
// Derived classes MUST override this method and compute a hash code that combines:
// a unique hash code seed, the base implementation result, and the
// hash codes of all new fields introduced by the derived class which are used
// in the CheckForSameDefinition method.
@Override
protected int computeCurrentDefinitionHashCode() {
return HashCode.combine(SquareRootScalar.class.hashCode(),
super.computeCurrentDefinitionHashCode(),
getDefinitionHashCode(m_scalar));
}
// Called to enumerate all of the other objects on which this object depends. This
// allows clients to navigate the graph of objects related to a computation.
@Override
public void enumerateDependencies(DependencyEnumerator enumerator) {
super.enumerateDependencies(enumerator);
enumerator.enumerate(m_scalar);
}
// The scalar that this scalar is the square root of.
public final Scalar getScalarToTakeSquareRootOf() {
return m_scalar;
}
public final void setScalarToTakeSquareRootOf(Scalar value) {
m_scalar = value;
}
// This method is responsible for returning an instance of the private
// Evaluator class. It should ensure that the properties are not null or
// in an invalid state, and then use the evaluator group when it constructs
// and returns an instance of the Evaluator.
@Override
public ScalarEvaluator getEvaluator(EvaluatorGroup group) {
if (group == null) {
throw new ArgumentNullException("group");
}
// Ensure that the properties are not null.
if (getScalarToTakeSquareRootOf() == null) {
throw new PropertyInvalidException("ScalarToTakeSquareRootOf", PropertyInvalidException.PropertyCannotBeNull);
}
return group.createEvaluator(getEvaluatorCallback);
}
private ScalarEvaluator createEvaluator(EvaluatorGroup group) {
// In order to take the square root of the scalar, we must first evaluate it.
// Get the evaluator that will allow us to do so.
// Notice that we create this evaluator in the same EvaluatorGroup.
ScalarEvaluator scalarEvaluator = getScalarToTakeSquareRootOf().getEvaluator(group);
return new Evaluator(group, scalarEvaluator);
}
private final EvaluatorGroup.Callback0<ScalarEvaluator> getEvaluatorCallback = EvaluatorGroup.Callback0.of(this::createEvaluator);
private Scalar m_scalar;
// This is the definition of the Evaluator that is used to actually evaluate this Scalar.
// Because it is a private, nested class, it is not visible outside of the SquareRootScalar class.
// This is ok, though, because once it is created users only interact with it via a reference
// to its base class: ScalarEvaluator.
private static final class Evaluator extends ScalarEvaluator {
// An evaluator should not store any data that the user will be able to change
// after creating the evaluator. This sometimes requires that data required by the
// evaluator be copied or frozen using the IFreezable interface.
public Evaluator(EvaluatorGroup group, ScalarEvaluator scalarEvaluator) {
super(group);
m_scalarEvaluator = scalarEvaluator;
}
// The Evaluator's copy constructor will be called from the Clone method.
// Don't forget to call the base class implementation!
private Evaluator(Evaluator existingInstance, CopyContext context) {
super(existingInstance, context);
// For non-evaluator reference types, we would use context.updateReference to
// allow the context to update the references we hold.
// This evaluator does not have any non-evaluator reference fields.
// For evaluators, just assign the reference directly - we'll call updateReference later.
m_scalarEvaluator = existingInstance.m_scalarEvaluator;
// Always call updateEvaluatorReferences at the end of the copy constructor.
// This is where references to evaluators will be updated.
updateEvaluatorReferences(context);
}
// This method is used by the EvaluatorGroup system to avoid redundant evaluations. The
// EvaluatorGroup may call it on your evaluator in order to replace your evaluator's
// reference to another evaluator with a reference to a version that caches its last
// result.
@Override
public void updateEvaluatorReferences(CopyContext context) {
m_scalarEvaluator = context.updateReference(m_scalarEvaluator);
}
// The clone method should call the copy constructor.
@Override
public Object clone(CopyContext context) {
return new Evaluator(this, context);
}
// This method determines if there is data available from this Evaluator at
// the specified date.
@Override
public boolean isAvailable(JulianDate date) {
// This evaluator is available whenever the nested evaluator is available.
return m_scalarEvaluator.isAvailable(date);
}
// This method returns a collection of time intervals when data is
// available from this Evaluator.
@Override
public TimeIntervalCollection getAvailabilityIntervals(TimeIntervalCollection consideredIntervals) {
// This evaluator is available whenever the nested evaluator is available.
return m_scalarEvaluator.getAvailabilityIntervals(consideredIntervals);
}
// This property determines if this Evaluator can safely be used from multiple threads
// simultaneously. If the evaluator stores data during the evaluate call, it is not thread
// safe. Otherwise, it generally is thread safe as long as any nested evaluators it uses
// are thread safe.
@Override
public boolean getIsThreadSafe() {
// This evaluator is thread safe as long as the nested evaluator is thread safe.
return m_scalarEvaluator.getIsThreadSafe();
}
// This property determines if this Evaluator result changes depending on the time at which it is evaluated.
@Override
public boolean getIsTimeVarying() {
return m_scalarEvaluator.getIsTimeVarying();
}
// This is where we do the actual evaluation when only the value of the scalar (not additional derivatives)
// is required.
@Override
public Double evaluate(JulianDate date) {
double value = m_scalarEvaluator.evaluate(date);
return Math.sqrt(value);
}
// This is where we do the actual evaluation when additional derivatives of the scalar
// are requested as well.
@Override
public Motion1<Double> evaluate(JulianDate date, int order) {
Motion1<Double> motion = m_scalarEvaluator.evaluate(date, order);
// Since only the second derivative is implemented here, constrain the array to
// only return up to that order.
int size = Math.min(motion.getOrder(), 2);
Double[] result = new Double[size + 1];
result[0] = Math.sqrt(motion.get(0));
// If the user did not request higher derivatives, do not spend time calculating them.
if (order > 0) {
// Compute the derivative using the chain rule.
result[1] = 0.5 * Math.pow(motion.get(0), -0.5) * motion.get(1);
}
if (order > 1) {
result[2] = 0.5 * Math.pow(motion.get(0), -0.5) * motion.get(2) - 0.25 * Math.pow(motion.get(0), -1.5) * motion.get(1) * motion.get(1);
}
return new Motion1<>(result);
}
// Override the dispose method to call the dispose() method on any nested
// evaluators or other disposable nested types.
@Override
protected void dispose(boolean disposing) {
if (disposing) {
m_scalarEvaluator.dispose();
}
}
private ScalarEvaluator m_scalarEvaluator;
}
}
Modifier | Constructor and Description |
---|---|
protected |
Vector()
Initializes a new instance.
|
protected |
Vector(Vector existingInstance,
CopyContext context)
Initializes a new instance as a copy of an existing instance.
|
Modifier and Type | Method and Description |
---|---|
Vector |
add(Vector vector)
Add a vector to this one.
|
static Vector |
add(Vector left,
Vector right)
Add two vectors together.
|
protected boolean |
checkForSameDefinition(DefinitionalObject other)
Checks to determine if another instance has the same definition as this instance and
returns
true if it does. |
protected abstract boolean |
checkForSameDefinition(Vector other)
Checks to determine if another instance has the same definition as this instance and
returns
true if it does. |
protected int |
computeCurrentDefinitionHashCode()
Computes a hash code based on the current properties of this object.
|
Vector |
createVectorDerivative(int order,
Axes axes)
Constructs a vector which represents a derivative of this vector.
|
Vector |
cross(Vector vector)
Produce the vector cross product between this vector and another one.
|
Vector |
divide(double factor)
Divide this vector by a scale factor.
|
Vector |
divide(Scalar factor)
Divide this vector by a scale factor.
|
static Vector |
divide(Vector vector,
double factor)
Divide a vector by a scalar.
|
static Vector |
divide(Vector vector,
Scalar factor)
Divide a vector by a scalar.
|
Scalar |
dot(Vector vector)
Produce the vector dot product between this vector and another one.
|
VectorEvaluator |
getEvaluator()
|
abstract VectorEvaluator |
getEvaluator(EvaluatorGroup group)
Gets an evaluator that can be used to find the
Motion <Cartesian >
of this vector in its parent Axes
at a given JulianDate . |
Scalar |
getScalarElement(CartesianElement element,
Axes referenceAxes)
Gets a
Scalar representing the X, Y, Z, or Magnitude of this vector. |
Scalar |
getScalarElement(CartesianElement element,
Axes referenceAxes,
int order)
Gets a
Scalar representing the X, Y, Z, or Magnitude of this vector,
or any derivative of those elements. |
Object |
getService(Class<?> serviceType)
Gets the service object of the specified type.
|
Vector |
multiply(double factor)
Multiply this vector by a scale factor.
|
static Vector |
multiply(double factor,
Vector vector)
Multiply a vector by a scalar.
|
Vector |
multiply(Scalar factor)
Multiply this vector by a scale factor.
|
static Vector |
multiply(Scalar factor,
Vector vector)
Multiply a vector by a scalar.
|
static Vector |
multiply(Vector vector,
double factor)
Multiply a vector by a scalar.
|
static Vector |
multiply(Vector vector,
Scalar factor)
Multiply a vector by a scalar.
|
Vector |
subtract(Vector vector)
Subtract a vector from this one.
|
static Vector |
subtract(Vector left,
Vector right)
Subtract one vector from another.
|
areSameDefinition, areSameDefinition, areSameDefinition, areSameDefinition, areSameDefinition, clone, collectionItemsAreSameDefinition, collectionItemsAreSameDefinition, collectionItemsAreSameDefinition, dictionaryItemsAreSameDefinition, enumerateDependencies, freeze, freezeAggregatedObjects, getCollectionHashCode, getCollectionHashCode, getCollectionHashCode, getDefinitionHashCode, getDefinitionHashCode, getDefinitionHashCode, getDefinitionHashCode, getDefinitionHashCode, getDefinitionHashCode, getDictionaryHashCode, getIsFrozen, isSameDefinition, throwIfFrozen
protected Vector()
protected Vector(@Nonnull Vector existingInstance, @Nonnull CopyContext context)
See ICloneWithContext.clone(CopyContext)
for more information about how to implement this constructor
in a derived class.
existingInstance
- The existing instance to copy.context
- A CopyContext
that controls the depth of the copy.ArgumentNullException
- Thrown when existingInstance
or context
is null
.protected final boolean checkForSameDefinition(DefinitionalObject other)
true
if it does. Derived classes MUST override this method and check
all new fields introduced by the derived class for definitional equivalence. It is NOT necessary
to check base class fields because the base class will already have done that. When overriding this method,
you should NOT call the base implementation because it will return false
for all derived-class instances.
Derived classes should check the type of other
to preserve the symmetric nature of IEquatableDefinition.isSameDefinition(java.lang.Object)
.checkForSameDefinition
in class DefinitionalObject
other
- The other instance to compare to this one.true
if the two objects are defined equivalently; otherwise false
.protected abstract boolean checkForSameDefinition(Vector other)
true
if it does. Derived classes MUST override this method and check
all new fields introduced by the derived class for definitional equivalence. It is NOT necessary
to check base class fields because the base class will already have done that. When overriding this method,
you should NOT call the base implementation because it will return false
for all derived-class instances.
Derived classes should check the type of other
to preserve the symmetric nature of IEquatableDefinition.isSameDefinition(java.lang.Object)
.other
- The other instance to compare to this one.true
if the two objects are defined equivalently; otherwise false
.protected int computeCurrentDefinitionHashCode()
Vector.checkForSameDefinition(agi.foundation.infrastructure.DefinitionalObject)
method.computeCurrentDefinitionHashCode
in class DefinitionalObject
@Nullable public Object getService(@Nonnull Class<?> serviceType)
getService
in interface IServiceProvider
serviceType
- An object that specifies the type of service object to get.null
if the service does not exist.ArgumentNullException
- Thrown when serviceType
is null
.@Nonnull public Vector createVectorDerivative(int order, Axes axes)
@Nonnull public final VectorEvaluator getEvaluator()
Motion
<Cartesian
>
of this vector at a given date with respect to the axes in which it is defined.
See Vector.getEvaluator(EvaluatorGroup)
for details.@Nonnull public abstract VectorEvaluator getEvaluator(@Nonnull EvaluatorGroup group)
Motion
<Cartesian
>
of this vector in its parent Axes
at a given JulianDate
.
Consider using the methods of GeometryTransformer
instead of calling this method directly.group
- The group with which to associate the new evaluator. By grouping evaluators
that are often evaluated at the same Julian dates, common computations can be performed only once
for the entire group instead of multiple times for each evaluator.@Nonnull public final Scalar getScalarElement(@Nonnull CartesianElement element, Axes referenceAxes, int order)
Scalar
representing the X, Y, Z, or Magnitude of this vector,
or any derivative of those elements.element
- The desired element of this vector (X, Y, Z or Magnitude).referenceAxes
- The axes to view this vector in.order
- The order of the derivative.Scalar
representing the desired element of this vector.@Nonnull public final Scalar getScalarElement(@Nonnull CartesianElement element, Axes referenceAxes)
Scalar
representing the X, Y, Z, or Magnitude of this vector.element
- The desired element of this vector (X, Y, Z or Magnitude).referenceAxes
- The axes to view this vector in.Scalar
representing the desired element of this vector.@Nonnull public Vector add(@Nonnull Vector vector)
vector
- The vector to add.@Nonnull public Vector subtract(@Nonnull Vector vector)
vector
- The vector to subtract.@Nonnull public Vector multiply(@Nonnull Scalar factor)
factor
- The factor to multiply.@Nonnull public Vector multiply(double factor)
factor
- The factor to multiply.@Nonnull public Vector divide(@Nonnull Scalar factor)
factor
- The factor to divide.@Nonnull public Vector divide(double factor)
factor
- The factor to divide.@Nonnull public final Vector cross(@Nonnull Vector vector)
vector
- The vector to cross with this one.@Nonnull public final Scalar dot(@Nonnull Vector vector)
vector
- The vector to dot with this one.public static Vector add(Vector left, Vector right)
left
- The left hand vector to add.right
- The right hand vector to add.public static Vector subtract(Vector left, Vector right)
left
- The left hand vector from which to subtract the right hand vector.right
- The right hand vector to subtract from the left hand vector.public static Vector multiply(Vector vector, Scalar factor)
vector
- The vector to scale.factor
- The scale factor.public static Vector multiply(Scalar factor, Vector vector)
vector
- The vector to scale.factor
- The scale factor.public static Vector multiply(Vector vector, double factor)
vector
- The vector to scale.factor
- The scale factor.public static Vector multiply(double factor, Vector vector)
vector
- The vector to scale.factor
- The scale factor.public static Vector divide(Vector vector, Scalar factor)
vector
- The vector to scale.factor
- The scale factor.