add get_quat() and get_uniform_scale()

This commit is contained in:
David Rose 2002-06-20 00:12:41 +00:00
parent bd3d94ccec
commit bc946860e6
3 changed files with 319 additions and 34 deletions

View File

@ -63,6 +63,19 @@ make_hpr(const LVecBase3f &hpr) {
LVecBase3f(1.0f, 1.0f, 1.0f));
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::make_quat
// Access: Published, Static
// Description: Makes a new TransformState with the specified
// components.
////////////////////////////////////////////////////////////////////
INLINE CPT(TransformState) TransformState::
make_quat(const LQuaternionf &quat) {
return make_pos_quat_scale(LVecBase3f(0.0f, 0.0f, 0.0f),
quat,
LVecBase3f(1.0f, 1.0f, 1.0f));
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::make_pos_hpr
// Access: Published, Static
@ -168,15 +181,44 @@ has_components() const {
// Description: Returns true if the transform was specified
// componentwise, or false if it was specified with a
// general 4x4 matrix. If this is true, the components
// returned by get_pos(), get_hpr(), and get_scale()
// will be exactly those that were set; otherwise, these
// functions will return computed values.
// returned by get_pos() and get_scale() will be exactly
// those that were set; otherwise, these functions will
// return computed values. If this is true, the
// rotation may have been set either with a hpr trio or
// with a quaternion; hpr_given() or quat_given() can
// resolve the difference.
////////////////////////////////////////////////////////////////////
INLINE bool TransformState::
components_given() const {
return ((_flags & F_components_given) != 0);
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::hpr_given
// Access: Published
// Description: Returns true if the rotation was specified via a trio
// of Euler angles, false otherwise. If this is true,
// get_hpr() will be exactly as set; otherwise, it will
// return a computed value.
////////////////////////////////////////////////////////////////////
INLINE bool TransformState::
hpr_given() const {
return ((_flags & F_hpr_given) != 0);
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::quat_given
// Access: Published
// Description: Returns true if the rotation was specified via a
// quaternion, false otherwise. If this is true,
// get_quat() will be exactly as set; otherwise, it will
// return a computed value.
////////////////////////////////////////////////////////////////////
INLINE bool TransformState::
quat_given() const {
return ((_flags & F_quat_given) != 0);
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::has_pos
// Access: Published
@ -203,6 +245,19 @@ has_hpr() const {
return has_components();
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::has_quat
// Access: Published
// Description: Returns true if the transform's rotation component
// can be extracted out separately and described as a
// quaternion. This is generally true only when
// has_components() is true.
////////////////////////////////////////////////////////////////////
INLINE bool TransformState::
has_quat() const {
return has_components();
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::has_scale
// Access: Published
@ -215,6 +270,20 @@ has_scale() const {
return has_components();
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::has_uniform_scale
// Access: Published
// Description: Returns true if the scale is uniform across all three
// axes (and therefore can be expressed as a single
// number), or false if the transform has a different
// scale in different dimensions.
////////////////////////////////////////////////////////////////////
INLINE bool TransformState::
has_uniform_scale() const {
check_components();
return (_flags & F_uniform_scale) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::has_mat
// Access: Published
@ -243,17 +312,31 @@ get_pos() const {
////////////////////////////////////////////////////////////////////
// Function: TransformState::get_hpr
// Access: Published
// Description: Returns the hpr component of the transform. It is an
// error to call this if has_components() returned
// false.
// Description: Returns the rotation component of the transform as a
// trio of Euler angles. It is an error to call this if
// has_components() returned false.
////////////////////////////////////////////////////////////////////
INLINE const LVecBase3f &TransformState::
get_hpr() const {
check_components();
check_hpr();
nassertr(has_hpr(), _hpr);
return _hpr;
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::get_quat
// Access: Published
// Description: Returns the rotation component of the transform as a
// quaternion. It is an error to call this if
// has_components() returned false.
////////////////////////////////////////////////////////////////////
INLINE const LQuaternionf &TransformState::
get_quat() const {
check_quat();
nassertr(has_quat(), _quat);
return _quat;
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::get_scale
// Access: Published
@ -268,6 +351,20 @@ get_scale() const {
return _scale;
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::get_uniform_scale
// Access: Published
// Description: Returns the scale component of the transform, as a
// single number. It is an error to call this if
// has_uniform_scale() returned false.
////////////////////////////////////////////////////////////////////
INLINE float TransformState::
get_uniform_scale() const {
check_components();
nassertr(has_uniform_scale(), _scale[0]);
return _scale[0];
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::get_mat
// Access: Published
@ -309,6 +406,36 @@ check_components() const {
}
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::check_hpr
// Access: Private
// Description: Ensures that we know the hpr of the transform
// (or that we know they cannot be derived).
////////////////////////////////////////////////////////////////////
INLINE void TransformState::
check_hpr() const {
// This pretends to be a const function, even though it's not,
// because it only updates a transparent cache value.
if ((_flags & F_hpr_known) == 0) {
((TransformState *)this)->calc_hpr();
}
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::check_quat
// Access: Private
// Description: Ensures that we know the quat of the transform
// (or that we know they cannot be derived).
////////////////////////////////////////////////////////////////////
INLINE void TransformState::
check_quat() const {
// This pretends to be a const function, even though it's not,
// because it only updates a transparent cache value.
if ((_flags & F_quat_known) == 0) {
((TransformState *)this)->calc_quat();
}
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::check_mat
// Access: Private
@ -323,6 +450,21 @@ check_mat() const {
}
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::check_uniform_scale
// Access: Private
// Description: Should be called immediately after _scale (and
// F_has_components) is set, this checks for a uniform
// scale and sets the bit appropriately.
////////////////////////////////////////////////////////////////////
INLINE void TransformState::
check_uniform_scale() {
if (IS_NEARLY_EQUAL(_scale[0], _scale[1]) &&
IS_NEARLY_EQUAL(_scale[0], _scale[2])) {
_flags |= F_uniform_scale;
}
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::set_destructing
// Access: Private

View File

@ -206,7 +206,7 @@ TransformState::
bool TransformState::
operator < (const TransformState &other) const {
static const int significant_flags =
(F_is_invalid | F_is_identity | F_components_given);
(F_is_invalid | F_is_identity | F_components_given | F_hpr_given);
int flags = (_flags & significant_flags);
int other_flags = (other._flags & significant_flags);
@ -220,7 +220,8 @@ operator < (const TransformState &other) const {
return 0;
}
if ((_flags & F_components_given) != 0) {
if ((_flags & (F_components_given | F_hpr_given)) ==
(F_components_given | F_hpr_given)) {
// If the transform was specified componentwise, compare them
// componentwise.
int c = _pos.compare_to(other._pos);
@ -301,7 +302,33 @@ make_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr,
state->_pos = pos;
state->_hpr = hpr;
state->_scale = scale;
state->_flags = F_components_given | F_components_known | F_has_components;
state->_flags = F_components_given | F_hpr_given | F_components_known | F_hpr_known | F_has_components;
state->check_uniform_scale();
return return_new(state);
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::make_pos_quat_scale
// Access: Published, Static
// Description: Makes a new TransformState with the specified
// components.
////////////////////////////////////////////////////////////////////
CPT(TransformState) TransformState::
make_pos_quat_scale(const LVecBase3f &pos, const LQuaternionf &quat,
const LVecBase3f &scale) {
// Make a special-case check for the identity transform.
if (pos == LVecBase3f(0.0f, 0.0f, 0.0f) &&
quat == LQuaternionf::ident_quat() &&
scale == LVecBase3f(1.0f, 1.0f, 1.0f)) {
return make_identity();
}
TransformState *state = new TransformState;
state->_pos = pos;
state->_quat = quat;
state->_scale = scale;
state->_flags = F_components_given | F_quat_given | F_components_known | F_quat_known | F_has_components;
state->check_uniform_scale();
return return_new(state);
}
@ -333,10 +360,14 @@ make_mat(const LMatrix4f &mat) {
////////////////////////////////////////////////////////////////////
CPT(TransformState) TransformState::
set_pos(const LVecBase3f &pos) const {
if ((_flags & F_components_given) != 0) {
if (components_given()) {
// If we started with a componentwise transform, we keep it that
// way.
return make_pos_hpr_scale(pos, get_hpr(), get_scale());
if (quat_given()) {
return make_pos_quat_scale(pos, get_quat(), get_scale());
} else {
return make_pos_hpr_scale(pos, get_hpr(), get_scale());
}
} else {
// Otherwise, we have a matrix transform, and we keep it that way.
@ -350,7 +381,7 @@ set_pos(const LVecBase3f &pos) const {
// Function: TransformState::set_hpr
// Access: Published
// Description: Returns a new TransformState object that represents the
// original TransformState with its hpr component
// original TransformState with its rotation component
// replaced with the indicated value, if possible.
////////////////////////////////////////////////////////////////////
CPT(TransformState) TransformState::
@ -359,6 +390,19 @@ set_hpr(const LVecBase3f &hpr) const {
return make_pos_hpr_scale(get_pos(), hpr, get_scale());
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::set_quat
// Access: Published
// Description: Returns a new TransformState object that represents the
// original TransformState with its rotation component
// replaced with the indicated value, if possible.
////////////////////////////////////////////////////////////////////
CPT(TransformState) TransformState::
set_quat(const LQuaternionf &quat) const {
nassertr(has_components(), this);
return make_pos_quat_scale(get_pos(), quat, get_scale());
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::set_scale
// Access: Published
@ -369,7 +413,11 @@ set_hpr(const LVecBase3f &hpr) const {
CPT(TransformState) TransformState::
set_scale(const LVecBase3f &scale) const {
nassertr(has_components(), this);
return make_pos_hpr_scale(get_pos(), get_hpr(), scale);
if (quat_given()) {
return make_pos_quat_scale(get_pos(), get_quat(), scale);
} else {
return make_pos_hpr_scale(get_pos(), get_hpr(), scale);
}
}
////////////////////////////////////////////////////////////////////
@ -549,13 +597,25 @@ output(ostream &out) const {
out << lead << "pos " << get_pos();
lead = ' ';
}
if (!get_hpr().almost_equal(LVecBase3f(0.0f, 0.0f, 0.0f))) {
out << lead << "hpr " << get_hpr();
lead = ' ';
if (quat_given()) {
if (!get_quat().almost_equal(LQuaternionf::ident_quat())) {
out << lead << "quat " << get_quat();
lead = ' ';
}
} else {
if (!get_hpr().almost_equal(LVecBase3f(0.0f, 0.0f, 0.0f))) {
out << lead << "hpr " << get_hpr();
lead = ' ';
}
}
if (!get_scale().almost_equal(LVecBase3f(1.0f, 1.0f, 1.0f))) {
out << lead << "scale " << get_scale();
lead = ' ';
if (has_uniform_scale()) {
out << lead << "scale " << get_uniform_scale();
lead = ' ';
} else {
out << lead << "scale " << get_scale();
lead = ' ';
}
}
if (lead == '(') {
out << "(almost identity)";
@ -702,8 +762,9 @@ calc_components() {
if ((_flags & F_is_identity) != 0) {
_scale.set(1.0f, 1.0f, 1.0f);
_hpr.set(0.0f, 0.0f, 0.0f);
_quat = LQuaternionf::ident_quat();
_pos.set(0.0f, 0.0f, 0.0f);
_flags |= F_has_components;
_flags |= F_has_components | F_components_known | F_hpr_known | F_quat_known | F_uniform_scale;
} else {
// If we don't have components and we're not identity, the only
@ -712,16 +773,57 @@ calc_components() {
const LMatrix4f &mat = get_mat();
bool possible = decompose_matrix(mat, _scale, _hpr, _pos);
if (possible) {
// Some matrices can't be decomposed into scale, hpr, pos.
_flags |= F_has_components;
if (!possible) {
// Some matrices can't be decomposed into scale, hpr, pos. In
// this case, we now know that we cannot compute the components.
_flags |= F_components_known | F_hpr_known | F_quat_known;
// However, we can always get at least the pos.
mat.get_row3(_pos, 3);
} else {
// Otherwise, we do have the components, or at least the hpr.
_flags |= F_has_components | F_components_known | F_hpr_known;
check_uniform_scale();
}
}
_flags |= F_components_known;
// However, we can always get at least the pos.
mat.get_row3(_pos, 3);
}
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::calc_hpr
// Access: Private
// Description: Derives the hpr, from the matrix if necessary, or
// from the quat.
////////////////////////////////////////////////////////////////////
void TransformState::
calc_hpr() {
nassertv((_flags & F_is_invalid) == 0);
check_components();
if ((_flags & F_hpr_known) == 0) {
// If we don't know the hpr yet, we must have been given a quat.
// Decompose it.
nassertv((_flags & F_quat_known) != 0);
_hpr = _quat.get_hpr();
_flags |= F_hpr_known;
}
}
////////////////////////////////////////////////////////////////////
// Function: TransformState::calc_quat
// Access: Private
// Description: Derives the quat from the hpr.
////////////////////////////////////////////////////////////////////
void TransformState::
calc_quat() {
nassertv((_flags & F_is_invalid) == 0);
check_components();
if ((_flags & F_quat_known) == 0) {
// If we don't know the quat yet, we must have been given a hpr.
// Decompose it.
nassertv((_flags & F_hpr_known) != 0);
_quat.set_hpr(_hpr);
_flags |= F_quat_known;
}
}
////////////////////////////////////////////////////////////////////
@ -739,7 +841,7 @@ calc_mat() {
// If we don't have a matrix and we're not identity, the only
// other explanation is that we were constructed via components.
nassertv((_flags & F_components_known) != 0);
compose_matrix(_mat, _scale, _hpr, _pos);
compose_matrix(_mat, _scale, get_hpr(), _pos);
}
_flags |= F_mat_known;
}
@ -778,10 +880,20 @@ write_datagram(BamWriter *manager, Datagram &dg) {
} else if ((_flags & F_components_given) != 0) {
// A component-based transform.
int flags = F_components_given | F_components_known | F_has_components;
if ((_flags & F_quat_given) != 0) {
flags |= (F_quat_given | F_quat_known);
} else if ((_flags & F_hpr_given) != 0) {
flags |= (F_hpr_given | F_hpr_known);
}
dg.add_uint16(flags);
_pos.write_datagram(dg);
_hpr.write_datagram(dg);
if ((_flags & F_quat_given) != 0) {
_quat.write_datagram(dg);
} else {
get_hpr().write_datagram(dg);
}
_scale.write_datagram(dg);
} else {
@ -879,11 +991,19 @@ fillin(DatagramIterator &scan, BamReader *manager) {
_flags = scan.get_uint16();
if ((_flags & F_components_known) != 0) {
if ((_flags & F_components_given) != 0) {
// Componentwise transform.
_pos.read_datagram(scan);
_hpr.read_datagram(scan);
if ((_flags & F_quat_given) != 0) {
_quat.read_datagram(scan);
} else {
_hpr.read_datagram(scan);
// Holdover support for bams 4.0 or older: add these bits that
// should have been added when the bam was written.
_flags |= (F_hpr_given | F_hpr_known);
}
_scale.read_datagram(scan);
check_uniform_scale();
}
if ((_flags & F_mat_known) != 0) {

View File

@ -70,6 +70,7 @@ PUBLISHED:
static CPT(TransformState) make_invalid();
INLINE static CPT(TransformState) make_pos(const LVecBase3f &pos);
INLINE static CPT(TransformState) make_hpr(const LVecBase3f &hpr);
INLINE static CPT(TransformState) make_quat(const LQuaternionf &quat);
INLINE static CPT(TransformState) make_pos_hpr(const LVecBase3f &pos,
const LVecBase3f &hpr);
INLINE static CPT(TransformState) make_scale(float scale);
@ -77,6 +78,9 @@ PUBLISHED:
static CPT(TransformState) make_pos_hpr_scale(const LVecBase3f &pos,
const LVecBase3f &hpr,
const LVecBase3f &scale);
static CPT(TransformState) make_pos_quat_scale(const LVecBase3f &pos,
const LQuaternionf &quat,
const LVecBase3f &scale);
static CPT(TransformState) make_mat(const LMatrix4f &mat);
INLINE bool is_identity() const;
@ -84,17 +88,24 @@ PUBLISHED:
INLINE bool is_singular() const;
INLINE bool has_components() const;
INLINE bool components_given() const;
INLINE bool hpr_given() const;
INLINE bool quat_given() const;
INLINE bool has_pos() const;
INLINE bool has_hpr() const;
INLINE bool has_quat() const;
INLINE bool has_scale() const;
INLINE bool has_uniform_scale() const;
INLINE bool has_mat() const;
INLINE const LVecBase3f &get_pos() const;
INLINE const LVecBase3f &get_hpr() const;
INLINE const LQuaternionf &get_quat() const;
INLINE const LVecBase3f &get_scale() const;
INLINE float get_uniform_scale() const;
INLINE const LMatrix4f &get_mat() const;
CPT(TransformState) set_pos(const LVecBase3f &pos) const;
CPT(TransformState) set_hpr(const LVecBase3f &hpr) const;
CPT(TransformState) set_quat(const LQuaternionf &quat) const;
CPT(TransformState) set_scale(const LVecBase3f &scale) const;
CPT(TransformState) compose(const TransformState *other) const;
@ -144,26 +155,38 @@ private:
// This is the actual data within the TransformState.
INLINE void check_singular() const;
INLINE void check_components() const;
INLINE void check_hpr() const;
INLINE void check_quat() const;
INLINE void check_mat() const;
void calc_singular();
void calc_components();
void calc_hpr();
void calc_quat();
void calc_mat();
INLINE void check_uniform_scale();
INLINE void set_destructing();
INLINE bool is_destructing() const;
enum Flags {
F_is_identity = 0x0001,
F_is_singular = 0x0002,
F_singular_known = 0x0004,
F_singular_known = 0x0004, // set if we know F_is_singular
F_components_given = 0x0008,
F_components_known = 0x0010,
F_components_known = 0x0010, // set if we know F_has_components
F_has_components = 0x0020,
F_mat_known = 0x0040,
F_mat_known = 0x0040, // set if _mat is defined
F_is_invalid = 0x0080,
F_quat_given = 0x0100,
F_quat_known = 0x0200, // set if _quat is defined
F_hpr_given = 0x0400,
F_hpr_known = 0x0800, // set if _hpr is defined
F_uniform_scale = 0x1000,
F_is_destructing = 0x8000,
};
LVecBase3f _pos, _hpr, _scale;
LQuaternionf _quat;
LMatrix4f _mat;
LMatrix4f *_inv_mat;