home *** CD-ROM | disk | FTP | other *** search
- //
- // Linear-Affine-Projective Geometry Package
- //
- // GeOb.C
- //
- // $Header$
- //
- // William J.R. Longabaugh
- // University of Washington
- //
- // Implementation of the linear-affine-projective geometry
- // package described in William J.R. Longabaugh, "An Expanded
- // System for Coordinate-Free Geometric Programming", Master's
- // thesis, University of Washington, 1992.
- //
- // Copyright (c) 1992, William J.R. Longabaugh
- // Copying, use and development for non-commercial purposes permitted.
- // All rights for commercial use reserved.
- // This software is unsupported and without warranty; it is
- // provided "as is".
- //
- // ***********************************************************************
- //
- // Notes on efficiency:
- //
- // There is a note in the header file Geom.h on efficiency that is
- // applicable here. Unfortunately, the casting of GeObs from one type to
- // another is probably very common, and yet the "first cut"
- // implementation used here is incredibly inefficient. Part of the
- // problem is that the functions to do the casting (e.g. GeOb
- // GeOb::MapTo(GeObType t)) use functions provided to the user (e.g. GeOb
- // Map::operator()(GeOb& v)) to do their job. This means that LOTS of
- // redundant checks are being done, and the object is being copied MANY
- // times during the course of the casting (thanks to the functional
- // semantics of the user functions). The next cut at improving the
- // implementation should provide special functions, available ONLY to the
- // implementing classes, that place their results in a designated
- // location and avoid type checking/casting their arguments, e.g.
- // GeOb Map::Apply(GeOb& v, GeOb* out);
- // This approach would help a lot at making things more efficient.
- //
- // Lots of implementing functions use the approach to call CanMap()
- // first to check if a map will succeed, and then calling MapTo(). They
- // do this to make error messages to the user more meaningful, since
- // errors will be reported by the function the user calls, and not a
- // function lower down. However, this is very inefficient, since it
- // means the GeOb is being checked if it is OK more than once. A better
- // approach would have GeObs providing the function
- // Boolean GeOb::MapTo(GeObType t, GeOb* out);
- // (ONLY to the implementing classes) that would avoid object copying
- // and return FALSE if the mapping could not be done.
- //
- // ***********************************************************************
-
- #include <math.h>
- #include "Lap.h"
-
- static Scalar randval(void);
-
- // ***********************************************************************
- //
- // This function returns a NON-ZERO integer in the range -10.0 to +10.0,
- // cast to a Scalar:
- //
-
- #define RAND_RANGE 20
-
- static Scalar randval()
- {
- #ifdef c_plusplus
- long random();
- #endif
-
- Scalar retval;
-
- while (TRUE) {
- retval = (Scalar)((random() % RAND_RANGE) - (RAND_RANGE / 2));
- if (retval != 0.0) break;
- }
- return retval;
- }
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // GeOb Class
- //
- // ***********************************************************************
- // ***********************************************************************
- //
- // Private/protected member functions
- //
- // ***********************************************************************
- //
- // Used by various classes to create GeObs with given matrix
- // representation:
- //
-
- GeOb::GeOb(GeObType g, Space& ins, Matrix& inm) : s(ins), m(inm)
- {
- type = ANY_GEOB;
- holds = g;
- }
-
- // ***********************************************************************
- //
- // Dumps data for GeObs:
- //
-
- void GeOb::data_out(ostream &c, int indent, char* name)
- {
- char *ibloc = new char[indent + 1];
- for (int i = 0; i < indent; i++) {
- *(ibloc + i) = ' ';
- }
- *(ibloc + indent) = '\0';
-
- c << ibloc << ast;
- c << ibloc << name;
- c << ibloc << "Type of GeOb: ";
- GeObTypeOut(c, type);
- c << "\n";
- c << ibloc << "Currently holds: ";
- GeObTypeOut(c, holds);
- c << "\n";
- if (holds != NULL_GEOB) {
- c << ibloc << "Contained in space:\n";
- s.debug_out(c, indent + ERR_IND);
- c << ibloc << "Matrix representation of the object:\n";
- m.debug_out(c, indent + ERR_IND);
- }
- c << ibloc << ast;
-
- delete ibloc;
- return;
- }
-
- // ***********************************************************************
- //
- // Public member functions
- //
- // ***********************************************************************
- //
- // Need to do memberwise initialization, since Matrix class members need
- // to do memberwise initialization:
- //
-
- GeOb::GeOb(GeOb& g) : s(g.s), m(g.m)
- {
- type = ANY_GEOB;
- holds = g.holds;
- }
-
- // ***********************************************************************
- //
- // Need to do memberwise assignment, since Matrix class members need
- // to do memberwise assignment:
- //
-
- GeOb& GeOb::operator=(GeOb& g)
- {
- // If there is a mismatch between what the arg. holds and the type
- // of this Geob, and this geob is not an ANY_GEOB, we need to cast.
- // This checking needs to be done because of apparent assignment
- // inheritance in g++ 1.37:
-
- if ((type != ANY_GEOB) && (type != g.holds) && (g.holds != NULL_GEOB)) {
- *this = g.MapTo(type);
- } else {
- holds = g.holds;
- s = g.s;
- m = g.m;
- }
- return (*this);
- }
-
- // ***********************************************************************
- //
- // Output for debugging:
- //
-
- void GeOb::debug_out(ostream &c, int indent)
- {
- static char* name = "GeOb Object\n";
- this->data_out(c, indent, name);
- return;
- }
-
- // ***********************************************************************
- //
- // If the multimap has zero arguments, we can cast it into a GeOb in
- // the range space. If it is a first-order map into the reals, it can
- // be cast into a vector in the dual space of the domain.
- //
-
- GeOb::GeOb(MultiMap& mp)
- {
- Boolean success = FALSE;
-
- type = ANY_GEOB;
-
- // Find out if it has zero arguments. If it does, do the cast.
- // Get the matrix rep. of the object. It is possible, if the type
- // is AFF_VECTOR, that the representation needs to be de-hoisted:
-
- if (mp.FullyEvaluated()) {
- m = mp.FullEvalRep();
- s = mp.RangeSpace();
- holds = s.NativeType();
- if ((holds == AFF_VECTOR) && (m.Columns() != s.MatrixSize())) {
- m *= Transpose(s.GetSpace(AFFINE).HoistTangent());
- }
- success = TRUE;
- } else {
-
- // Otherwise, check if it is a linear functional:
-
- Space range(mp.RangeSpace());
- Space domain(mp.DomainSpace());
-
- if ((mp.Holds() == MULTI_LINEAR) && (range == Reals) &&
- (domain.CPSpaceSize() == 1)) {
- s = domain.Dual();
- m = Matrix(1, s.MatrixSize());
- holds = s.NativeType();
- for (int i = 0; i < s.MatrixSize(); i++) {
- m[0][i] = (mp.GetStdImage(i))[0][0];
- }
- success = TRUE;
- }
- }
-
- // If it is neither, we have an error:
-
- if (!success) {
- errh.ErrorExit("GeOb::GeOb(MultiMap&)",
- "MultiMap cannot be cast to a GeOb", mp);
- }
- }
-
- // ***********************************************************************
- //
- // Casts maps that are unrestricted linear functionals into dual vectors:
- //
-
- GeOb::GeOb(Map& mp)
- {
- // Check the range and domain of the map. If the domain is not a
- // subset, and the range is the Reals, the map can be converted
- // into a Vector in the dual space of the domain:
-
- SubSet Range(mp.Range());
- SubSet Domain(mp.Domain());
- Space embeds(Range.EmbeddingSpace());
-
- type = ANY_GEOB;
-
- if ((mp.Holds() == LIN_MAP) && (embeds == Reals) &&
- Range.IsFullSpace() && Domain.IsFullSpace()) {
- s = (Domain.EmbeddingSpace()).Dual();
- m = Transpose(mp.MatrixRep());
- holds = s.NativeType();
- } else {
- errh.ErrorExit("GeOb::GeOb(Map&)",
- "Map is not an unrestricted linear functional", mp);
- }
- }
-
- // ***********************************************************************
- //
- // Casts Scalars into vectors in the predefined space "Reals", using
- // the standard basis, i.e. "1":
- //
-
- GeOb::GeOb(Scalar v) : s(Reals), m(IdentityMatrix(1) * v)
- {
- type = ANY_GEOB;
- holds = VECTOR;
- }
-
- // ***********************************************************************
- //
- // Says if the GeOb is (or can be mapped to) a zero vector:
- //
-
- Boolean GeOb::IsZeroVector(void)
- {
- Matrix mat = m;
-
- if ((holds != VECTOR) && (holds != AFF_VECTOR)) {
- GeOb temp = this->MapTo(VECTOR);
- mat = temp.m;
- }
-
- for (int i = 0; i < s.Dim(); i++) {
- if (fabs(mat[0][i]) > EPSILON) {
- return (FALSE);
- }
- }
- return (TRUE);
- }
-
- // ***********************************************************************
- //
- // This returns the nth element of a vector or point tuple (a vector
- // or point in a cartesian product space).
- //
-
- GeOb GeOb::operator[](int n)
- {
- GeOb temp(*this);
-
- // By storing points using a standard frame, point
- // extraction is pretty straightforward. If we were to
- // use a simplex, we would need to sum some coordinates to get
- // the coordinates to return.
-
- // This only works if this GeOb is a vector, aff_vector, or point.
- // If it is not, map it into the linearization space. No other attempt
- // will be made to "find" a space that is a CP space. (The user may need to
- // explicitly apply standard maps).
-
- if ((holds != VECTOR) && (holds != AFF_VECTOR) && (holds != AFF_POINT)) {
- temp = this->MapTo(VECTOR);
- }
-
- // Check that the integer is in the correct range:
-
- Space tempsp(temp.SpaceOf());
- if ((n >= tempsp.CPSpaceSize()) || (n < 0)) {
- errh.ErrorExit("GeOb GeOb::operator[](int)",
- "Specified n is invalid",
- ErrVal("Value of n = ", n), temp);
- }
-
- // If the mapped object is an atomic object, just return it:
-
- if (tempsp.CPSpaceSize() == 1) {
- return (temp);
- }
-
- // Get the nth space in the tuple and its coordinate starting slot,
- // and figure out the size of the matrix to build:
-
- Space retspace = tempsp[n];
- int slot = tempsp.StartSlot(n);
-
- // Build the matrix. If this is a point, we need to tack on the
- // trailing 1:
-
- Matrix retmat(1, retspace.MatrixSize());
- for (int i = 0; i < retspace.Dim(); i++) {
- retmat[0][i] = (temp.m)[0][slot++];
- }
- if (retspace.Holds() == AFF_SPACE) {
- retmat[0][retspace.Dim()] = 1.0;
- }
-
- GeOb retval(retspace.NativeType(), retspace, retmat);
- return (retval);
- }
-
- // ***********************************************************************
- //
- // Like the above function, but it extracts all the elements from
- // the tuple and returns them in a list:
-
- GeObList GeOb::TupleElements(void)
- {
- GeOb temp(*this);
-
- // Same comments apply here as with above function.
-
- if ((holds != VECTOR) && (holds != AFF_VECTOR) && (holds != AFF_POINT)) {
- temp = this->MapTo(VECTOR);
- }
-
- // Loop through all the elements, creating a new GeOb for each element,
- // and adding it to the list of GeObs that is returned.
- // (But if the mapped object is an atomic object, just return it):
-
- Space tempsp(temp.SpaceOf());
- int n = tempsp.CPSpaceSize();
- GeObList retlist(n);
-
- if (tempsp.CPSpaceSize() == 1) {
- retlist[0] = temp;
- return (retlist);
- }
-
- for (int j = 0; j < n; j++) {
- Space retspace = tempsp[j];
- int slot = tempsp.StartSlot(j);
-
- // Build the matrix. If this is a point, we need to tack on the
- // trailing 1:
-
- Matrix retmat(1, retspace.MatrixSize());
- for (int i = 0; i < retspace.Dim(); i++) {
- retmat[0][i] = (temp.m)[0][slot++];
- }
- if (retspace.Holds() == AFF_SPACE) {
- retmat[0][retspace.Dim()] = 1.0;
- }
-
- retlist[j] = GeOb(retspace.NativeType(), retspace, retmat);
- }
- return (retlist);
- }
-
- // ***********************************************************************
- //
- // IMPORTANT NOTE ON ALGEBRAIC AND APPLICATION OPERATIONS:
- //
- // In the following operations, it is considered to make sense to
- // use these operators on vector equivalence classes (ec) (and affine
- // vector equivalence classes). Since casting ec to vectors
- // or affine vectors returns random elements, the result of the
- // operations will also be typically random. While it is not
- // recommended to use the operations on ec, the operations are
- // included for completeness.
- //
- // ***********************************************************************
- //
- // FRIEND FUNCTION
- // If the object is a vector, negate it. Otherwise, map it into
- // the linearization space and negate it there (though try to keep
- // operations in tangent spaces localized there).
- //
-
- GeOb operator-(GeOb& th)
- {
- if ((th.holds == VECTOR) || (th.holds == AFF_VECTOR)) {
- GeOb retval(th.holds, th.s, -(th.m));
- return (retval);
- } else if (th.holds == AFF_VEC_EC) {
- GeOb retval = th.MapTo(AFF_VECTOR);
- retval.m = -(retval.m);
- return (retval);
- } else {
- GeOb retval = th.MapTo(VECTOR);
- retval.m = -(retval.m);
- return (retval);
- }
- }
-
- // ***********************************************************************
- //
- // FRIEND FUNCTION
- // If both objects are vectors in the same space, add them. Try to
- // keep operations in tangent spaces localized there. Otherwise,
- // map objects to their Linearization spaces and add them there if the
- // spaces match.
- //
-
- GeOb operator+(GeOb& th, GeOb& g)
- {
- static char* sig = "GeOb operator+(GeOb&, GeOb&)";
-
- if (((th.holds == VECTOR) && (g.holds == VECTOR)) ||
- ((th.holds == AFF_VECTOR) && (g.holds == AFF_VECTOR))) {
- if (th.s == g.s) {
- GeOb retval(th.holds, th.s, th.m + g.m);
- return (retval);
- } else {
- errh.ErrorExit(sig, "Spaces of operands do not match", th, g);
- }
- } else if (((th.holds == AFF_VECTOR) || (th.holds == AFF_VEC_EC)) &&
- ((g.holds == AFF_VEC_EC) || (g.holds == AFF_VECTOR))) {
- GeOb retval = th.MapTo(AFF_VECTOR);
- GeOb other = g.MapTo(AFF_VECTOR);
- if (retval.s == other.s) {
- retval.m = retval.m + other.m;
- return (retval);
- } else {
- errh.ErrorExit(sig, "Spaces of operands do not match", th, g);
- }
- } else {
- GeOb retval = th.MapTo(VECTOR);
- GeOb other = g.MapTo(VECTOR);
- if (retval.s == other.s) {
- retval.m = retval.m + other.m;
- return (retval);
- } else {
- errh.ErrorExit(sig, "Spaces of mapped operands do not match",
- th, g, retval, other);
- }
- }
- }
-
- // ***********************************************************************
- //
- // FRIEND FUNCTION
- // Handle subtraction just like addition:
- //
-
- GeOb operator-(GeOb& th, GeOb& g)
- {
- static char* sig = "GeOb operator-(GeOb&, GeOb&)";
-
- if (((th.holds == VECTOR) && (g.holds == VECTOR)) ||
- ((th.holds == AFF_VECTOR) && (g.holds == AFF_VECTOR))) {
- if (th.s == g.s) {
- GeOb retval(th.holds, th.s, th.m - g.m);
- return (retval);
- } else {
- errh.ErrorExit(sig, "Spaces of operands do not match", th, g);
- }
- } else if (((th.holds == AFF_VECTOR) || (th.holds == AFF_VEC_EC)) &&
- ((g.holds == AFF_VEC_EC) || (g.holds == AFF_VECTOR))) {
- GeOb retval = th.MapTo(AFF_VECTOR);
- GeOb other = g.MapTo(AFF_VECTOR);
- if (retval.s == other.s) {
- retval.m = retval.m - other.m;
- return (retval);
- } else {
- errh.ErrorExit(sig, "Spaces of operands do not match", th, g);
- }
- } else {
- GeOb retval = th.MapTo(VECTOR);
- GeOb other = g.MapTo(VECTOR);
- if (retval.s == other.s) {
- retval.m = retval.m - other.m;
- return (retval);
- } else {
- errh.ErrorExit(sig, "Spaces of mapped operands do not match",
- th, g, retval, other);
- }
- }
- }
-
- // ***********************************************************************
- //
- // FRIEND FUNCTION
- // This operation only make sense if one of the operands is a Vector
- // in the special 1-dim space "Reals", in which case this is scalar
- // multiplication. While it would be very nice to be able to define
- // functions like "GeOb operator*(Scalar coeff, GeOb& g)" for efficient
- // scalar multiplication, compiler ambiguity prevents this from being
- // possible:
- //
-
- GeOb operator*(GeOb& th, GeOb& g)
- {
- GeOb temp;
- Scalar coeff;
-
- if (th.s == Reals) {
- coeff = th.ToScalar();
- temp = g;
- } else if (g.s == Reals) {
- coeff = g.ToScalar();
- temp = th;
- } else {
- errh.ErrorExit("GeOb operator*(GeOb&, GeOb&)",
- "Neither operand was a vector in space Reals", th, g);
- }
-
- // Try to keep operations local to tangent vector spaces:
-
- if (temp.holds == AFF_VEC_EC) {
- temp = temp.MapTo(AFF_VECTOR);
- } else if ((temp.holds != VECTOR) && (temp.holds != AFF_VECTOR)) {
- temp = temp.MapTo(VECTOR);
- }
-
- temp.m = temp.m * coeff;
- return (temp);
- }
-
- // ***********************************************************************
- //
- // FRIEND FUNCTION
- // Same as multiplication, using a reciprocal. The second argument
- // must be the vector from the Reals, and it must be non-zero. Again
- // having a function "GeOb operator/(GeOb& g, Scalar coeff)" would
- // be great, but must be avoided to prevent compiler ambiguity:
- //
-
- GeOb operator/(GeOb& th, GeOb& g)
- {
- static char* sig = "GeOb operator/(GeOb&, GeOb&)";
- Scalar coeff;
-
- if (g.s == Reals) {
- coeff = g.ToScalar();
- } else {
- errh.ErrorExit(sig, "Second operand was not a vector in space Reals",
- th, g);
- }
-
- if (fabs(coeff) < EPSILON) {
- errh.ErrorExit(sig, "Attempt to divide by zero",
- ErrVal("Value of denominator = ", coeff), th);
- }
-
- // Try to keep operations local to tangent vector spaces:
-
- if ((th.holds == VECTOR) || (th.holds == AFF_VECTOR)) {
- GeOb retval(th.holds, th.s, th.m / coeff);
- return (retval);
- } else if (th.holds == AFF_VEC_EC) {
- GeOb retval = th.MapTo(AFF_VECTOR);
- retval.m = retval.m / coeff;
- return (retval);
- } else {
- GeOb retval = th.MapTo(VECTOR);
- retval.m = retval.m / coeff;
- return (retval);
- }
- }
-
- // ***********************************************************************
- //
- // Apply this object to the argument, which should be in the dual space.
- // Try to keep operations local to tangent vector spaces if possible.
- //
-
- Scalar GeOb::Apply(GeOb& a)
- {
- static char* sig = "Scalar GeOb::Apply(GeOb&)";
-
- // One of the objects is going to be in a dual space, and cannot
- // be mapped (except maybe from an equivalence class). The other
- // object should be mapped to the native type of the dual space.
-
- GeObType firsttype;
- GeObType othertype;
- SRel thisrel = s.ThisSpaceIs();
- SRel otherrel = a.SpaceOf().ThisSpaceIs();
- if ((thisrel == TANG_DUAL) || (thisrel == LIN_DUAL)) {
- firsttype = s.NativeType();
- othertype = s.Dual().NativeType();
- } else if ((otherrel == TANG_DUAL) || (otherrel == LIN_DUAL)) {
- firsttype = a.SpaceOf().Dual().NativeType();
- othertype = a.SpaceOf().NativeType();
- } else {
- errh.ErrorExit(sig, "One item must be in a dual space", *this, a);
- }
- GeOb first = this->MapTo(firsttype);
- GeOb other = a.MapTo(othertype);
- if (first.SpaceOf() == (other.SpaceOf()).Dual()) {
- return ((first.m * Transpose(other.m))[0][0]);
- } else {
- errh.ErrorExit(sig, "Spaces of mapped operands are not duals",
- *this, a, first, other);
- }
- }
-
- // ***********************************************************************
- //
- // If the GeOb is a vector in a space that has a distinguished inner
- // product (i.e. it is a Euclidean Vector Space), there is a
- // mapping between vectors and dual vectors: v -> < ,v>.
- //
-
- GeOb GeOb::Dual(void)
- {
- static char* sig = "Vector GeOb::Dual(void)";
- GeObList hold(2);
-
- // This implementation uses the robust way to find the dual: partially
- // evaluate the inner product MLM using this vector, then cast the
- // resulting linear functional into the dual vector. While taking the
- // transpose is MUCH faster, future changes to the system that permit
- // arbitrary distinguished products would break the transpose route.
-
- if ((holds == VECTOR) || (holds == AFF_VECTOR)) {
- if (s.IsEuclidean()) {
- hold[0] = *this;
- return ((s.InnerProduct())(s, hold));
- } else {
- errh.ErrorExit(sig, "Vector in not in a Euclidean space", *this);
- }
- }
- // If this GeOb is an affine vector ec, cast it to an affine vector.
- // Otherwise cast it to a vector and go:
-
- GeObType maptype = ((holds == AFF_VEC_EC) ? AFF_VECTOR : VECTOR);
- GeOb mapped = this->MapTo(maptype);
- if ((mapped.SpaceOf()).IsEuclidean()) {
- hold[0] = mapped;
- return ((mapped.SpaceOf().InnerProduct())(mapped.SpaceOf(), hold));
- } else {
- errh.ErrorExit(sig, "Mapped object not in a Euclidean space",
- *this, mapped);
- }
- }
-
- // ***********************************************************************
- //
- // Returns TRUE iff this object can be cast to the specified object.
- // Code is so specific to each type of GeOb that it was decided to
- // cast this GeOb down and let functions tailored for each type do
- // the work. While this localizes the implementation, the use of
- // downcasting is TERRIBLE for efficiency, since it means this
- // GeOb is being recopied prior to the operation being performed:
- //
-
- Boolean GeOb::CanMapTo(GeObType t)
- {
- Boolean rv;
-
- // Quick kill:
-
- if (t == holds) return (TRUE);
-
- // Need to cover all cases. Need to ask if this object is in
- // the domain of the standard mapping to the given type.
-
- switch (holds) {
- case VECTOR:
- rv = Vector(*this).CanMapTo(t);
- break;
- case AFF_POINT:
- rv = APoint(*this).CanMapTo(t);
- break;
- case AFF_VECTOR:
- rv = AVector(*this).CanMapTo(t);
- break;
- case VEC_EC:
- rv = VectorEC(*this).CanMapTo(t);
- break;
- case AFF_VEC_EC:
- rv = AVectorEC(*this).CanMapTo(t);
- break;
- case PROJ_POINT:
- rv = PPoint(*this).CanMapTo(t);
- break;
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit("Boolean GeOb::CanMapTo(GeObType)", "Illegal GeOb type",
- ErrType("Type found =", holds, GEOBTYPES), *this);
- break;
- }
- return (rv);
- }
-
- // ***********************************************************************
- //
- // This is the way to get the GeOb that results from standard mappings.
- // Code is so specific to each type of GeOb that it was decided to
- // cast this GeOb down and let functions tailored for each type do
- // the work. Unfortunately, while this approach localizes the
- // implementation, the use of downcasting is TERRIBLE for efficiency,
- // since it involves this GeOb being recopied prior to the operation
- // being performed (in fact, it means MapTo() is being called AGAIN,
- // though it only executes the "quick kill" base case). This is
- // particulary harmful for system efficiency given the frequency of
- // mapping in many common operations (map application, algebraic
- // operations). Another approach may be more desirable.
- //
-
- GeOb GeOb::MapTo(GeObType t)
- {
- GeOb rv;
-
- // Quick kill:
-
- if (t == holds) return (*this);
-
- // Need to cover all cases.
-
- switch (holds) {
- case VECTOR:
- rv = Vector(*this).MapTo(t);
- break;
- case AFF_POINT:
- rv = APoint(*this).MapTo(t);
- break;
- case AFF_VECTOR:
- rv = AVector(*this).MapTo(t);
- break;
- case VEC_EC:
- rv = VectorEC(*this).MapTo(t);
- break;
- case AFF_VEC_EC:
- rv = AVectorEC(*this).MapTo(t);
- break;
- case PROJ_POINT:
- rv = PPoint(*this).MapTo(t);
- break;
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit("GeOb GeOb::MapTo(GeObType)", "Illegal GeOb type",
- ErrType("Type found =", holds, GEOBTYPES), *this);
- break;
- }
- return (rv);
- }
-
- // ***********************************************************************
- //
- // It would be nice to be able to SET tuple elements using the []
- // operator, but this doesn't work since a tuple is not implemented
- // as a set of GeObs, and so we cannot return a reference to one of them.
- //
-
- GeOb GeOb::SetTupleElement(int n, GeOb& g)
- {
- static char* sig = "GeOb GeOb::SetTupleElement(int, GeOb&)";
- GeOb temp(*this);
-
- // First, this only works if this GeOb is a vector, aff_vector, or point.
- // If it is not, map it into the linearization space. No other attempt
- // will be made to "find" a space that is a CP space. (The user may need to
- // explicitly apply standard maps).
-
- if ((holds != VECTOR) && (holds != AFF_VECTOR) && (holds != AFF_POINT)) {
- temp = this->MapTo(VECTOR);
- }
-
- // Check that the integer is in the correct range:
-
- Space tempsp(temp.SpaceOf());
- if ((n >= tempsp.CPSpaceSize()) || (n < 0)) {
- errh.ErrorExit(sig, "Specified n is invalid",
- ErrVal("Value of n = ", n), temp);
- }
-
- // If the mapped object is in an atomic space, setting the element
- // reduces to returning the mapped argument GeOb, as long as the
- // spaces match:
-
- if (tempsp.CPSpaceSize() == 1) {
- GeOb retval = g.MapTo(tempsp.NativeType());
- if (tempsp == retval.SpaceOf()) {
- return (retval);
- } else {
- errh.ErrorExit(sig, "Mapped GeOb is not in required space",
- temp, tempsp, g, retval);
- }
- }
-
- // Get the nth space in the tuple and its coordinate starting slot.
- // Map the object to the necessary type:
-
- Space slotspace = tempsp[n];
- int slot = tempsp.StartSlot(n);
- GeOb insert = g.MapTo(slotspace.NativeType());
-
- // Check that the spaces match, and if they do, replace the
- // coordinates in the required slots and return:
-
- if (slotspace == insert.SpaceOf()) {
- Matrix retmat(temp.m);
- for (int i = 0; i < slotspace.Dim(); i++) {
- retmat[0][slot++] = (insert.m)[0][i];
- }
- GeOb retval = GeOb(temp.Holds(), tempsp, retmat);
- return (retval);
- } else {
- errh.ErrorExit(sig, "Mapped GeOb is not in required space",
- temp, slotspace, g, insert);
- }
- }
-
- // ***********************************************************************
- //
- // FRIEND FUNCTION
- // Correspondence of GeObList is INFINITY->A, 0->B, 1->C.
- // Given CR = (A,B;C,D) and list (A,B,C), this returns D:
- //
-
- PPoint CrossRatio(AugScalar v, GeObList& g)
- {
- static char* sig = "GeOb GeOb::CrossRatio(AugScalar, GeObList&)";
- int i;
-
- // The GeObList must consist of 3 objects that can be cast to
- // co-linear points in the projective completion.
-
- if (g.Length() != 3) {
- errh.ErrorExit(sig, "List must contain 3 items", g);
- }
-
- // Cast the first GeOb and glean inportant info.
-
- GeOb temp = g[0].MapTo(PROJ_POINT);
- Space retsp = temp.SpaceOf();
- int numcol = retsp.MatrixSize();
- Matrix holdmat(2, numcol);
- Matrix unitmat(1, numcol);
- holdmat[0] = (temp.m)[0];
-
- // Go through the rest of the list, casting and storing the
- // matrix representation:
-
- for (i = 1; i < 3; i++) {
- temp = g[i].MapTo(PROJ_POINT);
- if (temp.SpaceOf() != retsp) {
- errh.ErrorExit(sig, "All items do not map to same space", g);
- }
- if (i == 1) {
- holdmat[1] = (temp.m)[0];
- } else {
- unitmat[0] = (temp.m)[0];
- }
- }
-
- // We need to make sure that the points are distinct and that they
- // are all co-linear. Then we need to scale the rows
- // of the matrix so they sum to the unit point matrix.
-
- // Build an orthogonal basis using the first two vectors:
-
- Matrix orthbas(2, numcol);
- Scalar mag = sqrt((holdmat[0] * Transpose(holdmat[0]))[0][0]);
- orthbas[0] = (holdmat[0] / mag)[0];
- Scalar fac = (holdmat[1] * Transpose(orthbas[0]))[0][0];
- orthbas[1] = (holdmat[1] - (fac * orthbas[0]))[0];
- mag = sqrt((orthbas[1] * Transpose(orthbas[1]))[0][0]);
- if (fabs(mag) < EPSILON) {
- errh.ErrorExit(sig, "First two points are not distinct", g);
- }
- orthbas[1] = (orthbas[1] / mag)[0];
-
- // Project the third point into the plane, and make sure this projection
- // is essentially superfluous:
-
- Matrix newunit = unitmat * Transpose(orthbas);
-
- Matrix test = (newunit * orthbas) - unitmat;
- for (i = 0; i < numcol; i++) {
- if (fabs(test[0][i]) > EPSILON) {
- errh.ErrorExit(sig, "Points are not collinear", g);
- }
- }
-
- // Find how to scale the rows of the mapping matrix so they sum to
- // the unit point:
-
- Matrix coeff = newunit * Inverse(holdmat * Transpose(orthbas));
- if ((fabs(coeff[0][0]) < EPSILON) || (fabs(coeff[0][1]) < EPSILON)) {
- errh.ErrorExit(sig, "Third point is not distinct", g);
- }
- holdmat[0] = (holdmat[0] * coeff[0][0])[0];
- holdmat[1] = (holdmat[1] * coeff[0][1])[0];
-
- // That's it! Holdmat now holds the map from extended reals to
- // all points on the line, so map and return:
-
- GeOb retval(PROJ_POINT, retsp, v.GetMatrix() * holdmat);
- return PPoint(retval);
- }
-
- // ***********************************************************************
- //
- // FRIEND FUNCTION
- // Given a list of four collinear points (A,B,C,D) where at least
- // three are distinct, this routine calculates the cross ratio
- // (A,B;C,D).
- //
-
- AugScalar CrossRatioCalc(GeObList& g)
- {
- static char* sig = "AugScalar GeOb::CrossRatioCalc(GeObList&)";
- int i;
-
- // The GeObList must consist of 4 objects that can be cast to
- // co-linear points in the projective completion:
-
- if (g.Length() != 4) {
- errh.ErrorExit(sig, "List must contain 4 items", g);
- }
-
- // Cast the first GeOb and glean inportant info.
-
- GeOb temp = g[0].MapTo(PROJ_POINT);
- Space chksp = temp.SpaceOf();
- int numcol = chksp.MatrixSize();
- Matrix holdmat(4, numcol);
- holdmat[0] = (temp.m)[0];
-
- // Go through the rest of the list, casting and storing the
- // matrix representation:
-
- for (i = 1; i < 4; i++) {
- temp = g[i].MapTo(PROJ_POINT);
- if (temp.SpaceOf() != chksp) {
- errh.ErrorExit(sig, "All items do not map to same space", g);
- }
- holdmat[i] = (temp.m)[0];
- }
-
- // Build an orthogonal basis using the first two distinct points. If
- // we encounter a duplication, just try the next point. If that also
- // doesn't work, we have an error:
-
- Boolean havedup = FALSE;
- Matrix orthbas(2, numcol);
- Scalar mag = sqrt((holdmat[0] * Transpose(holdmat[0]))[0][0]);
- orthbas[0] = (holdmat[0] / mag)[0];
-
- Matrix candidate = holdmat[1];
- for (int trycount = 1; trycount <= 3; trycount++) {
- if (trycount == 3) {
- errh.ErrorExit(sig, "Three points are not distinct", g);
- }
- Scalar fac = (candidate * Transpose(orthbas[0]))[0][0];
- orthbas[1] = (candidate - (fac * orthbas[0]))[0];
- mag = sqrt((orthbas[1] * Transpose(orthbas[1]))[0][0]);
- if (fabs(mag) < EPSILON) {
- candidate = holdmat[2];
- havedup = TRUE;
- } else {
- orthbas[1] = (orthbas[1] / mag)[0];
- break;
- }
- }
-
- // Project the points into the line specified by the basis we
- // have constructed, and make sure this projection is essentially
- // superfluous:
-
- Matrix ppts(4, 2);
-
- for (i = 0; i < 4; i++) {
- ppts[i] = (holdmat[i] * Transpose(orthbas))[0];
- Matrix testm = (ppts[i] * orthbas) - holdmat[i];
- for (int j = 0; j < numcol; j++) {
- if (fabs(testm[0][j]) > EPSILON) {
- errh.ErrorExit(sig, "Points are not collinear", g);
- }
- }
- }
-
- // Use this 2-dim representation to calculate the cross product,
- // using the formulation in Penna & Patterson pg. 163:
-
- Scalar fac[4];
-
- fac[0] = (ppts[0][0] * ppts[2][1]) - (ppts[2][0] * ppts[0][1]);
- fac[1] = (ppts[1][0] * ppts[3][1]) - (ppts[3][0] * ppts[1][1]);
- fac[2] = (ppts[1][0] * ppts[2][1]) - (ppts[2][0] * ppts[1][1]);
- fac[3] = (ppts[0][0] * ppts[3][1]) - (ppts[3][0] * ppts[0][1]);
-
- // Catch cases where we do not have enough distinct points:
-
- Boolean iszero[4];
- Boolean haveazero = FALSE;
- Boolean multizero = FALSE;
- Boolean allequal = TRUE;
- for (i = 0; i < 4; i++) {
- iszero[i] = (fabs(fac[i]) < EPSILON);
- multizero = (multizero || (haveazero && iszero[i]));
- haveazero = (haveazero || iszero[i]);
- allequal = allequal && (fabs(fac[i] - fac[0]) < EPSILON);
- }
-
- if (multizero || allequal) {
- errh.ErrorExit(sig, "Must have 3 distinct points", g);
- }
-
- AugScalar retval;
- Scalar denom = fac[2] * fac[3];
- if (fabs(denom) < EPSILON) {
- retval = AugScalar(INFINITY);
- } else {
- retval = AugScalar((fac[0] * fac[1]) / denom);
- }
- return retval;
- }
-
- // ***********************************************************************
- //
- // Cast a GeOb that is in the one-dimensional space "Reals" into a
- // Scalar. Cannot use operator Scalar() because resulting automatic
- // casting causes ambiguity in algebraic operations.
- //
-
- Scalar GeOb::ToScalar(void)
- {
- if (s == Reals) {
- return (m[0][0]);
- } else {
- errh.ErrorExit("Scalar GeOb::ToScalar(void)",
- "Attempted to convert a GeOb not in space Reals to a scalar",
- *this);
- }
- }
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // Vector Class
- //
- // ***********************************************************************
- // ***********************************************************************
- //
- // Public member functions
- //
- // ***********************************************************************
- //
- // Creates a vector tuple with two elements.
- //
-
- Vector::Vector(VSpace& ins, GeOb& v1, GeOb& v2)
- {
- type = VECTOR;
- *this = Vector(ins, GeObList(v1, v2));
- }
-
- // ***********************************************************************
- //
- // Creates a vector tuple with three elements.
- //
-
- Vector::Vector(VSpace& ins, GeOb& v1, GeOb& v2, GeOb& v3)
- {
- type = VECTOR;
- *this = Vector(ins, GeObList(v1, v2, v3));
- }
-
- // ***********************************************************************
- //
- // Need to do memberwise assignment, since matrix class members need
- // to do memberwise assignment:
- //
-
- Vector& Vector::operator=(Vector& g)
- {
- holds = g.holds;
- s = g.s;
- m = g.m;
- return (*this);
- }
-
- // ***********************************************************************
- //
- // Output for debugging:
- //
-
- void Vector::debug_out(ostream &c, int indent)
- {
- static char* name = "Vector Object\n";
- this->data_out(c, indent, name);
- return;
- }
-
- // ***********************************************************************
- //
- // Vector creation by specifying coordinates:
- //
-
- Vector::Vector(VBasis& b, ScalarList& a)
- {
- static char* sig = "Vector::Vector(VBasis&, ScalarList&)";
-
- type = VECTOR;
- holds = VECTOR;
- s = b.SpaceOf();
-
- if (s.ThisSpaceIs() == TANGENT) {
- errh.ErrorExit(sig, "Basis is not in a non-tangent vector space", b, a);
- }
-
- if (a.Length() != s.Dim()) {
- errh.ErrorExit(sig, "Incorrect number of coordinates specified", b, a);
- }
-
- Matrix hold(1, s.Dim());
- for (int i = 0; i < s.Dim(); i++) {
- hold[0][i] = a[i];
- }
- m = hold * b.Tostdb();
- }
-
- // ***********************************************************************
- //
- // Creates a vector tuple in the specified cartesian product space using
- // the objects in the list:
- //
-
- Vector::Vector(VSpace& ins, GeObList &g)
- {
- static char* sig = "Vector::Vector(VSpace&, GeObList&)";
-
- type = VECTOR;
- holds = VECTOR;
- s = ins;
- m = Matrix(1, ins.MatrixSize());
-
- // The space must be a non-Tangent Vector Space. The length of the list
- // must be correct:
-
- if (ins.NativeType() != VECTOR) {
- errh.ErrorExit(sig, "Space is a tangent vector space", ins);
- }
-
- int n = g.Length();
- if (n != ins.CPSpaceSize()) {
- errh.ErrorExit(sig,
- "Length of list does not match number of elements in space",
- ins, g);
- }
-
- // Go through the list of objects, casting them into vectors or
- // affine vectors as needed. Report an error if the object cannot
- // be mapped into the required space:
-
- for (int j = 0; j < n; j++) {
-
- // Get the nth space in the tuple and its coordinate starting slot.
- // Map the object to the necessary type:
-
- Space slotspace = ins[j];
- int slot = ins.StartSlot(j);
- GeOb insert = (g[j]).MapTo(slotspace.NativeType());
-
- // Check that the spaces match, and if they do, replace the
- // coordinates in the required slots and go to the next object:
-
- if (slotspace == insert.SpaceOf()) {
- for (int i = 0; i < slotspace.Dim(); i++) {
- m[0][slot++] = (insert.MatrixRep())[0][i];
- }
- } else {
- errh.ErrorExit(sig, "Mapped GeOb is not in required space",
- slotspace, g[j], insert);
- }
- }
- }
-
- // ***********************************************************************
-
- Boolean Vector::CanMapTo(GeObType t)
- {
- Boolean rv;
-
- // Quick kill:
-
- if (t == holds) return (TRUE);
-
- if ((s.ThisSpaceIs() == TANG_DUAL) || (s.ThisSpaceIs() == LIN_DUAL)) {
- rv = ((t == VEC_EC) && !(this->IsZeroVector()));
- } else {
- switch (t) {
- case AFF_POINT:
- rv = (s.StdAffineSubset()).IsIn(*this);
- break;
- case AFF_VECTOR:
- rv = ((s.LinearMapToRef(TANGENT)).Domain()).IsIn(*this);
- break;
- case AFF_VEC_EC:
- rv = ((s.LinearMapToRef(TANGENT)).Domain()).IsIn(*this) &&
- !(this->IsZeroVector());;
- break;
- case VEC_EC:
- rv = !(this->IsZeroVector());
- break;
- case PROJ_POINT:
- rv = (s.StdAffineSubset()).IsIn(*this);
- break;
- case VECTOR:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit("Boolean Vector::CanMapTo(GeObType)",
- "Illegal GeOb Type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- }
- return (rv);
- }
-
- // ***********************************************************************
-
- GeOb Vector::MapTo(GeObType t)
- {
- static char* sig = "GeOb Vector::MapTo(GeObType)";
- GeOb rv;
-
- // Quick kill:
-
- if (t == holds) return (*this);
-
- if ((s.ThisSpaceIs() == TANG_DUAL) || (s.ThisSpaceIs() == LIN_DUAL)) {
- if ((t == VEC_EC) && !(this->IsZeroVector())) {
- rv = GeOb(VEC_EC, s, m);
- } else {
- errh.ErrorExit(sig, "Impossible Map request", *this,
- ErrType("Mapping from:", holds, GEOBTYPES),
- ErrType("Mapping to:", t, GEOBTYPES));
- }
- } else {
- switch (t) {
- case AFF_POINT:
- rv = (s.AffineMapToRef(AFFINE))(*this);
- break;
- case AFF_VECTOR:
- rv = (s.LinearMapToRef(TANGENT))(*this);
- break;
- case AFF_VEC_EC:
- if (!this->IsZeroVector()) {
- rv = (s.LinearMapToRef(TANGENT))(*this);
- rv = GeOb(AFF_VEC_EC, rv.SpaceOf(), rv.MatrixRep());
- } else {
- errh.ErrorExit(sig, "Can't map zero vector to affine vec. eq. class",
- *this);
- }
- break;
- case VEC_EC:
- if (!this->IsZeroVector()) {
- rv = GeOb(VEC_EC, s, m);
- } else {
- errh.ErrorExit(sig, "Can't map zero vector to vec. eq. class",
- *this);
- }
- break;
- case PROJ_POINT:
- rv = (s.AffineMapToRef(PROJECT_COMP))(*this);
- break;
- case VECTOR:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit(sig, "Illegal GeOb type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- }
- return (rv);
- }
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // AVector Class
- //
- // ***********************************************************************
- // ***********************************************************************
- //
- // Public member functions
- //
- // ***********************************************************************
-
- AVector::AVector(VSpace& ins, GeOb& v1, GeOb& v2)
- {
- type = AFF_VECTOR;
- *this = AVector(ins, GeObList(v1, v2));
- }
-
- // ***********************************************************************
-
- AVector::AVector(VSpace& ins, GeOb& v1, GeOb& v2, GeOb& v3)
- {
- type = AFF_VECTOR;
- *this = AVector(ins, GeObList(v1, v2, v3));
- }
-
- // ***********************************************************************
- //
- // Need to do memberwise assignment, since matrix class members need
- // to do memberwise assignment:
- //
-
- AVector& AVector::operator=(AVector& g)
- {
- holds = g.holds;
- s = g.s;
- m = g.m;
- return (*this);
- }
-
- // ***********************************************************************
- //
- // Output for debugging:
- //
-
- void AVector::debug_out(ostream &c, int indent)
- {
- static char* name = "AVector Object\n";
- this->data_out(c, indent, name);
- return;
- }
-
- // ***********************************************************************
- //
- // Vector creation by specifying coordinates wrt some basis:
- //
-
- AVector::AVector(Basis& b, ScalarList& a)
- {
- static char* sig = "AVector::AVector(Basis&, ScalarList&)";
- int n;
- Matrix dropdown;
-
- type = AFF_VECTOR;
- holds = AFF_VECTOR;
-
- switch (b.Holds()) {
- case FRAME:
- case SIMPLEX:
- s = (b.SpaceOf()).GetSpace(TANGENT);
- n = b.SpaceOf().MatrixSize();
- if (a.Length() != n) {
- errh.ErrorExit(sig, "Incorrect number of coordinates specified", b, a);
- }
- dropdown = Transpose((b.SpaceOf()).HoistTangent());
- if (b.Holds() == SIMPLEX) {
- Scalar sum = 0.0;
- for (int i = 0; i < n; i++) {
- sum += a[i];
- }
- if (fabs(sum) > EPSILON) {
- errh.ErrorExit(sig, "Scalars must sum to 0.0 for a simplex",
- ErrVal("Sum = ", sum), a, b);
- }
- } else if (fabs(a[n - 1]) > EPSILON) {
- errh.ErrorExit(sig, "Last scalar must equal 0.0 for a frame",
- ErrVal("Value = ", a[n - 1]), b);
- }
- break;
- case VBASIS:
- s = b.SpaceOf();
- n = s.MatrixSize();
- if (a.Length() != n) {
- errh.ErrorExit(sig, "Incorrect number of coordinates specified", b, a);
- }
- dropdown = IdentityMatrix(n);
- break;
- case HFRAME:
- case NULL_BASIS:
- case ANY_BASIS:
- default:
- errh.ErrorExit(sig, "Illegal basis type", b);
- break;
- }
-
- // If a Frame or Simplex is used, we need to change the matrix representation
- // down to the tangent space:
-
- Matrix hold(1, n);
- for (int i = 0; i < n; i++) {
- hold[0][i] = a[i];
- }
- m = hold * b.Tostdb() * dropdown;
- }
-
- // ***********************************************************************
-
- AVector::AVector(VSpace& ins, GeObList& g)
- {
- static char* sig = "AVector::AVector(VSpace&, GeObList&)";
-
- type = AFF_VECTOR;
- holds = AFF_VECTOR;
- s = ins;
- m = Matrix(1, ins.MatrixSize());
-
- // The space must be a Tangent Vector Space. The length of the list
- // must be correct:
-
- if (ins.ThisSpaceIs() != TANGENT) {
- errh.ErrorExit(sig, "Space is not a tangent vector space", ins);
- }
-
- int n = g.Length();
- if (n != ins.CPSpaceSize()) {
- errh.ErrorExit(sig,
- "Length of list does not match number of elements in space",
- ins, g);
- }
-
- // Go through the list of objects, casting them into affine vectors as
- // needed. Report an error if the object cannot be mapped into the
- // required space:
-
- for (int j = 0; j < n; j++) {
-
- // Get the nth space in the tuple and its coordinate starting slot.
- // Map the object to the necessary type:
-
- Space slotspace = ins[j];
- int slot = ins.StartSlot(j);
- GeOb insert = (g[j]).MapTo(slotspace.NativeType());
-
- // Check that the spaces match, and if they do, replace the
- // coordinates in the required slots and go to the next object:
-
- if (slotspace == insert.SpaceOf()) {
- for (int i = 0; i < slotspace.Dim(); i++) {
- m[0][slot++] = (insert.MatrixRep())[0][i];
- }
- } else {
- errh.ErrorExit(sig, "Mapped GeOb is not in required space",
- slotspace, g[j], insert);
- }
- }
- }
-
- // ***********************************************************************
- //
- // Returns TRUE iff this AVector can be cast to the specified object:
- //
-
- Boolean AVector::CanMapTo(GeObType t)
- {
- Boolean rv;
-
- // Quick kill:
-
- if (t == holds) return (TRUE);
-
- switch (t) {
- case VECTOR:
- rv = TRUE;
- break;
- case AFF_VEC_EC:
- case VEC_EC:
- rv = !(this->IsZeroVector());
- break;
- case AFF_POINT:
- case PROJ_POINT:
- rv = FALSE;
- break;
- case AFF_VECTOR:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit("Boolean AVector::CanMapTo(GeObType)", "Illegal GeOb Type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- return (rv);
- }
-
- // ***********************************************************************
- //
- // Map the AVector to another type:
- //
-
- GeOb AVector::MapTo(GeObType t)
- {
- static char* sig = "GeOb AVector::MapTo(GeObType)";
- GeOb rv;
-
- // Quick kill:
-
- if (t == holds) return (*this);
-
- switch (t) {
- case VECTOR:
- rv = (s.LinearMapToRef(LINEARIZATION))(*this);
- break;
- case VEC_EC:
- if (!this->IsZeroVector()) {
- rv = (s.LinearMapToRef(LINEARIZATION))(*this);
- rv = GeOb(VEC_EC, rv.SpaceOf(), rv.MatrixRep());
- } else {
- errh.ErrorExit(sig, "Can't map zero vector to vector eq. class",
- *this);
- }
- break;
- case AFF_VEC_EC:
- if (!this->IsZeroVector()) {
- rv = GeOb(AFF_VEC_EC, s, m);
- } else {
- errh.ErrorExit(sig, "Can't map zero vector to affine vec. eq. class",
- *this);
- }
- break;
- case AFF_POINT:
- case PROJ_POINT:
- errh.ErrorExit(sig, "Impossible map request", *this,
- ErrType("Mapping from:", holds, GEOBTYPES),
- ErrType("Mapping to:", t, GEOBTYPES));
- break;
- case AFF_VECTOR:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit(sig, "Illegal GeOb type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- return (rv);
- }
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // VectorEC Class
- //
- // ***********************************************************************
- //
- // Public member functions
- //
- // ***********************************************************************
- //
- // Need to do memberwise assignment, since Matrix class members need
- // to do memberwise assignment:
- //
-
- VectorEC& VectorEC::operator=(VectorEC& g)
- {
- holds = g.holds;
- s = g.s;
- m = g.m;
- return (*this);
- }
-
- // ***********************************************************************
- //
- // Output for debugging:
- //
-
- void VectorEC::debug_out(ostream &c, int indent)
- {
- static char* name = "VectorEC Object\n";
- this->data_out(c, indent, name);
- return;
- }
-
- // ***********************************************************************
- //
- // Returns TRUE iff this VectorEC can be cast to the specified object:
- //
-
- Boolean VectorEC::CanMapTo(GeObType t)
- {
- Boolean rv;
-
- // Quick kill:
-
- if (t == holds) return (TRUE);
-
- if ((s.ThisSpaceIs() == TANG_DUAL) || (s.ThisSpaceIs() == LIN_DUAL)) {
- rv = (t == VECTOR);
- } else {
- switch (t) {
- case AFF_POINT:
- case AFF_VECTOR:
- case AFF_VEC_EC:
- {
- GeOb test = this->MapTo(VECTOR);
- rv = ((s.LinearMapToRef(TANGENT)).Domain()).IsIn(test);
- if (t == AFF_POINT) rv = !rv;
- }
- break;
- case VECTOR:
- case PROJ_POINT:
- rv = TRUE;
- break;
- case VEC_EC:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit("Boolean VectorEC::CanMapTo(GeObType)",
- "Illegal GeOb type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- }
- return (rv);
- }
-
- // ***********************************************************************
- //
- // Map this VectorEC to another object:
- //
-
- GeOb VectorEC::MapTo(GeObType t)
- {
- static char* sig = "GeOb VectorEC::MapTo(GeObType)";
- GeOb rv;
- Scalar coeff;
-
- // Quick kill:
-
- if (t == holds) return (*this);
-
- if ((s.ThisSpaceIs() == TANG_DUAL) || (s.ThisSpaceIs() == LIN_DUAL)) {
- if (t == VECTOR) {
- coeff = randval();
- rv = GeOb(VECTOR, s, m * coeff);
- } else {
- errh.ErrorExit(sig, "Impossible map request", *this,
- ErrType("Mapping from:", holds, GEOBTYPES),
- ErrType("Mapping to:", t, GEOBTYPES));
- }
- } else {
- switch (t) {
- case AFF_POINT:
- // Go through the back door, by mapping into projective space first!
- rv = (s.ProjectiveMapToRef(PROJECT_COMP))(*this);
- rv = ((rv.SpaceOf()).AffineMapToRef(AFFINE))(rv);
- break;
- case AFF_VECTOR:
- coeff = randval();
- rv = GeOb(VECTOR, s, m * coeff);
- rv = (s.LinearMapToRef(TANGENT))(rv);
- break;
- case AFF_VEC_EC:
- rv = GeOb(VECTOR, s, m);
- rv = (s.LinearMapToRef(TANGENT))(rv);
- rv = GeOb(AFF_VEC_EC, rv.SpaceOf(), rv.MatrixRep());
- break;
- case VECTOR:
- coeff = randval();
- rv = GeOb(VECTOR, s, m * coeff);
- break;
- case PROJ_POINT:
- rv = (s.ProjectiveMapToRef(PROJECT_COMP))(*this);
- break;
- case VEC_EC:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit(sig, "Illegal GeOb type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- }
- return (rv);
- }
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // AVectorEC Class
- //
- // ***********************************************************************
- // ***********************************************************************
- //
- // Public member functions
- //
- // ***********************************************************************
- //
- // Need to do memberwise assignment, since Matrix class members need
- // to do memberwise assignment:
- //
-
- AVectorEC& AVectorEC::operator=(AVectorEC& g)
- {
- holds = g.holds;
- s = g.s;
- m = g.m;
- return (*this);
- }
-
- // ***********************************************************************
- //
- // Output for debugging:
- //
-
- void AVectorEC::debug_out(ostream &c, int indent)
- {
- static char* name = "AVectorEC Object\n";
- this->data_out(c, indent, name);
- return;
- }
-
- // ***********************************************************************
- //
- // Returns TRUE iff this AVectorEC can be cast to the specified object:
- //
-
- Boolean AVectorEC::CanMapTo(GeObType t)
- {
- Boolean rv;
-
- // Quick kill:
-
- if (t == holds) return (TRUE);
-
- switch (t) {
- case AFF_VECTOR:
- case VEC_EC:
- case VECTOR:
- case PROJ_POINT:
- rv = TRUE;
- break;
- case AFF_POINT:
- rv = FALSE;
- break;
- case AFF_VEC_EC:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit("Boolean AVectorEC::CanMapTo(GeObType)",
- "Illegal GeOb type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- return (rv);
- }
-
- // ***********************************************************************
- //
- // This is the way to get the GeOb that results from standard mappings:
- //
-
- GeOb AVectorEC::MapTo(GeObType t)
- {
- static char* sig = "GeOb AVectorEC::MapTo(GeObType)";
- GeOb rv;
- Scalar coeff;
-
- // Quick kill:
-
- if (t == holds) return (*this);
-
- switch (t) {
- case VEC_EC:
- rv = GeOb(AFF_VECTOR, s, m);
- rv = (s.LinearMapToRef(LINEARIZATION))(rv);
- rv = GeOb(VEC_EC, rv.SpaceOf(), rv.MatrixRep());
- break;
- case VECTOR:
- coeff = randval();
- rv = GeOb(AFF_VECTOR, s, m * coeff);
- rv = (s.LinearMapToRef(LINEARIZATION))(rv);
- break;
- case AFF_VECTOR:
- coeff = randval();
- rv = GeOb(AFF_VECTOR, s, m * coeff);
- break;
- case PROJ_POINT:
- rv = GeOb(AFF_VECTOR, s, m);
- rv = (s.LinearMapToRef(LINEARIZATION))(rv);
- rv = GeOb(VEC_EC, rv.SpaceOf(), rv.MatrixRep());
- rv = (rv.SpaceOf().ProjectiveMapToRef(PROJECT_COMP))(rv);
- break;
- case AFF_POINT:
- errh.ErrorExit(sig, "Impossible map request", *this,
- ErrType("Mapping from:", holds, GEOBTYPES),
- ErrType("Mapping to:", t, GEOBTYPES));
- break;
- case AFF_VEC_EC:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit(sig, "Illegal GeOb type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- return (rv);
- }
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // APoint Class
- //
- // ***********************************************************************
- // ***********************************************************************
- //
- // Public member functions
- //
- // ***********************************************************************
-
- APoint::APoint(ASpace& ins, GeOb& v1, GeOb& v2)
- {
- type = AFF_POINT;
- *this = APoint(ins, GeObList(v1, v2));
- }
-
- // ***********************************************************************
-
- APoint::APoint(ASpace &ins, GeOb &v1, GeOb &v2, GeOb &v3)
- {
- type = AFF_POINT;
- *this = APoint(ins, GeObList(v1, v2, v3));
- }
-
- // ***********************************************************************
- //
- // Need to do memberwise assignment, since Matrix class members need
- // to do memberwise assignment:
- //
-
- APoint& APoint::operator=(APoint& g)
- {
- holds = g.holds;
- s = g.s;
- m = g.m;
- return (*this);
- }
-
- // ***********************************************************************
- //
- // Output for debugging:
- //
-
- void APoint::debug_out(ostream &c, int indent)
- {
- static char* name = "APoint Object\n";
- this->data_out(c, indent, name);
- return;
- }
-
- // ***********************************************************************
- //
- // APoint creation by specifying coordinates wrt some basis:
- //
-
- APoint::APoint(Basis& b, ScalarList& a)
- {
- static char* sig = "APoint::APoint(Basis&, ScalarList&)";
-
- holds = AFF_POINT;
- type = AFF_POINT;
- s = b.SpaceOf();
- int n = s.MatrixSize();
-
- if (a.Length() != n) {
- errh.ErrorExit(sig, "Incorrect number of coordinates specified", b, a);
- }
-
- if (b.Holds() == FRAME) {
- if (fabs(1.0 - a[n - 1]) > EPSILON) {
- errh.ErrorExit(sig, "Last scalar must equal 1.0 for a frame",
- ErrVal("Value = ", a[n - 1]), b);
- }
- } else if (b.Holds() == SIMPLEX) {
- Scalar sum = 0.0;
- for (int i = 0; i < n; i++) {
- sum += a[i];
- }
- if (fabs(1.0 - sum) > EPSILON) {
- errh.ErrorExit(sig, "Scalars must sum to 1.0 for a simplex",
- ErrVal("Sum = ", sum), a, b);
- }
- } else {
- errh.ErrorExit(sig, "Illegal basis type", b);
- }
-
- Matrix hold(1, n);
- for (int i = 0; i < n; i++) {
- hold[0][i] = a[i];
- }
- m = hold * b.Tostdb();
- }
-
- // ***********************************************************************
- //
- // Create a Point tuple:
- //
-
- APoint::APoint(ASpace& ins, GeObList& g)
- {
- static char* sig = "APoint::APoint(ASpace&, GeObList&)";
- int slot;
-
- type = AFF_POINT;
- holds = AFF_POINT;
- s = ins;
- m = Matrix(1, ins.MatrixSize());
-
- // The space must be an Affine Space. The length of the list must
- // be correct:
-
- int n = g.Length();
- if (n != ins.CPSpaceSize()) {
- errh.ErrorExit(sig,
- "Length of list does not match number of elements in space",
- ins, g);
- }
-
- // Go through the list of objects, casting them into points as needed.
- // Report an error if the object cannot be mapped into the required space:
-
- for (int j = 0; j < n; j++) {
-
- // Get the nth space in the tuple and its coordinate starting slot.
- // Map the object to the necessary type:
-
- Space slotspace = ins[j];
- slot = ins.StartSlot(j);
- GeOb insert = (g[j]).MapTo(AFF_POINT);
-
- // Check that the spaces match, and if they do, replace the
- // coordinates in the required slots and go to the next object:
-
- if (slotspace == insert.SpaceOf()) {
- for (int i = 0; i < slotspace.Dim(); i++) {
- m[0][slot++] = (insert.MatrixRep())[0][i];
- }
- } else {
- errh.ErrorExit(sig, "Mapped GeOb is not in required space",
- slotspace, g[j], insert);
- }
- }
-
- // The last slot must be 1.0:
-
- m[0][slot] = 1.0;
- }
-
- // ***********************************************************************
- //
- // Returns TRUE iff this APoint can be mapped to the specified type:
- //
-
- Boolean APoint::CanMapTo(GeObType t)
- {
- Boolean rv;
-
- // Quick kill:
-
- if (t == holds) return (TRUE);
-
- switch (t) {
- case AFF_VEC_EC:
- case AFF_VECTOR:
- rv = FALSE;
- break;
- case VECTOR:
- case VEC_EC:
- case PROJ_POINT:
- rv = TRUE;
- break;
- case AFF_POINT:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit("Boolean APoint::CanMapTo(GeObType)", "Illegal GeOb type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- return (rv);
- }
-
- // ***********************************************************************
- //
- // Maps this object to the specified type:
- //
-
- GeOb APoint::MapTo(GeObType t)
- {
- static char* sig = "GeOb APoint::MapTo(GeObType)";
- GeOb rv;
-
- // Quick kill:
-
- if (t == holds) return (*this);
-
- switch (t) {
- case VECTOR:
- rv = (s.AffineMapToRef(LINEARIZATION))(*this);
- break;
- case VEC_EC:
- rv = (s.AffineMapToRef(LINEARIZATION))(*this);
- rv = GeOb(VEC_EC, rv.SpaceOf(), rv.MatrixRep());
- break;
- case PROJ_POINT:
- rv = (s.AffineMapToRef(PROJECT_COMP))(*this);
- break;
- case AFF_VEC_EC:
- case AFF_VECTOR:
- errh.ErrorExit(sig, "Impossible map request", *this,
- ErrType("Mapping from:", holds, GEOBTYPES),
- ErrType("Mapping to:", t, GEOBTYPES));
- break;
- case AFF_POINT:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit(sig, "Illegal GeOb type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- return (rv);
- }
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // PPoint Class
- //
- // ***********************************************************************
- // ***********************************************************************
- //
- // Public member functions
- //
- // ***********************************************************************
- //
- // Need to do memberwise assignment, since Matrix class members need
- // to do memberwise assignment:
- //
-
- PPoint& PPoint::operator=(PPoint& g)
- {
- holds = g.holds;
- s = g.s;
- m = g.m;
- return (*this);
- }
-
- // ***********************************************************************
- //
- // Output for debugging:
- //
-
- void PPoint::debug_out(ostream &c, int indent)
- {
- static char* name = "PPoint Object\n";
- this->data_out(c, indent, name);
- return;
- }
-
- // ***********************************************************************
- //
- // Projective Point creation by specifying homogeneous coordinates:
- //
-
- PPoint::PPoint(HFrame& b, ScalarList& a)
- {
- type = PROJ_POINT;
- holds = PROJ_POINT;
- s = b.SpaceOf();
-
- if (a.Length() != s.MatrixSize()) {
- errh.ErrorExit("PPoint::PPoint(HFrame&, ScalarList&)",
- "Incorrect number of coordinates specified", b, a);
- }
-
- Matrix hold(1, s.MatrixSize());
- for (int i = 0; i < s.MatrixSize(); i++) {
- hold[0][i] = a[i];
- }
- m = hold * b.Tostdb();
- }
-
- // ***********************************************************************
- //
- // Returns TRUE iff the PPoint can be mapped to the specified object:
- //
-
- Boolean PPoint::CanMapTo(GeObType t)
- {
- Boolean rv;
-
- // Quick kill:
-
- if (t == holds) return (TRUE);
-
- switch (t) {
- case VECTOR:
- case AFF_POINT:
- rv = (s.StdAffineSubset()).IsIn(*this);
- break;
- case AFF_VEC_EC:
- rv = !((s.StdAffineSubset()).IsIn(*this));
- break;
- case AFF_VECTOR:
- rv = FALSE;
- break;
- case VEC_EC:
- rv = TRUE;
- break;
- case PROJ_POINT:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit("Boolean PPoint::CanMapTo(GeObType)", "Illegal GeOb type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- return (rv);
- }
-
- // ***********************************************************************
- //
- // This is the way to get the GeOb that results from standard mappings:
- //
-
- GeOb PPoint::MapTo(GeObType t)
- {
- static char* sig = "GeOb PPoint::MapTo(GeObType)";
- GeOb rv;
-
- // Quick kill:
-
- if (t == holds) return (*this);
-
- switch (t) {
- case VECTOR:
- rv = (s.AffineMapToRef(LINEARIZATION))(*this);
- break;
- case AFF_POINT:
- rv = (s.AffineMapToRef(AFFINE))(*this);
- break;
- case VEC_EC:
- rv = (s.ProjectiveMapToRef(LINEARIZATION))(*this);
- break;
- case AFF_VEC_EC:
- rv = (s.ProjectiveMapToRef(LINEARIZATION))(*this);
- rv = GeOb(VECTOR, rv.SpaceOf(), rv.MatrixRep());
- rv = (rv.SpaceOf().LinearMapToRef(TANGENT))(rv);
- rv = GeOb(AFF_VEC_EC, rv.SpaceOf(), rv.MatrixRep());
- break;
- case AFF_VECTOR:
- errh.ErrorExit(sig, "Impossible Map request", *this,
- ErrType("Mapping from:", holds, GEOBTYPES),
- ErrType("Mapping to:", t, GEOBTYPES));
- break;
- case PROJ_POINT:
- case NULL_GEOB:
- case ANY_GEOB:
- default:
- errh.ErrorExit(sig, "Illegal GeOb Type",
- ErrType("Type specified =", t, GEOBTYPES));
- break;
- }
- return (rv);
- }
-
- // ***********************************************************************
- // ***********************************************************************
- //
- // Create a "standard" Null GeOb that can be used for building lists
- // of geometric object arguments for partial multimap evaluation:
- //
-
- GeOb NullGeOb;
-
- // ***********************************************************************
-
-
-
-
-