/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * * All use of this software is subject to the terms of the revised BSD * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * * @file fltTransformRotateScale.cxx * @author drose * @date 2000-08-30 */ #include "fltTransformRotateScale.h" #include "fltRecordReader.h" #include "fltRecordWriter.h" #include "mathNumbers.h" #include "look_at.h" TypeHandle FltTransformRotateScale::_type_handle; /** * */ FltTransformRotateScale:: FltTransformRotateScale(FltHeader *header) : FltTransformRecord(header) { _center.set(0.0, 0.0, 0.0); _reference_point.set(0.0, 0.0, 0.0); _to_point.set(0.0, 0.0, 0.0); _overall_scale = 1.0; _axis_scale = 1.0; _angle = 0.0; } /** * Defines the transform explicitly. The angle of rotation is determined by * the angle between the reference point and the to point (relative to the * center), and the scale factor is determined by the distance between the * reference point and the center point. If axis_scale is true, the scale is * along reference point axis only; otherwise, it is a uniform scale. */ void FltTransformRotateScale:: set(const LPoint3d ¢er, const LPoint3d &reference_point, const LPoint3d &to_point, bool axis_scale) { _center = center; _reference_point = reference_point; _to_point = to_point; LVector3d v1 = _reference_point - _center; LVector3d v2 = _to_point - _center; _angle = acos(dot(normalize(v1), normalize(v2))) * 180.0 / MathNumbers::pi; if (axis_scale) { _axis_scale = length(v1); _overall_scale = 1.0; } else { _overall_scale = length(v1); _axis_scale = 1.0; } recompute_matrix(); } /** * */ const LPoint3d &FltTransformRotateScale:: get_center() const { return _center; } /** * */ const LPoint3d &FltTransformRotateScale:: get_reference_point() const { return _reference_point; } /** * */ const LPoint3d &FltTransformRotateScale:: get_to_point() const { return _to_point; } /** * Returns the overall scale factor. */ PN_stdfloat FltTransformRotateScale:: get_overall_scale() const { return _overall_scale; } /** * Returns the scale factor in the direction of the axis. */ PN_stdfloat FltTransformRotateScale:: get_axis_scale() const { return _axis_scale; } /** * Returns the angle of rotation in degrees. */ PN_stdfloat FltTransformRotateScale:: get_angle() const { return _angle; } /** * */ void FltTransformRotateScale:: recompute_matrix() { LVector3d v1 = _reference_point - _center; LVector3d v2 = _to_point - _center; LVector3d rotate_axis = normalize(cross(v1, v2)); // To scale along an axis, we have to do a bit of work. First determine the // matrices to rotate and unrotate the rotate axis to the y-forward axis. LMatrix4d r1; look_at(r1, v1, rotate_axis, CS_zup_right); _matrix = LMatrix4d::translate_mat(-_center) * r1 * LMatrix4d::scale_mat(1.0, _axis_scale, 1.0) * LMatrix4d::scale_mat(_overall_scale) * invert(r1) * LMatrix4d::rotate_mat(_angle, rotate_axis, CS_zup_right) * LMatrix4d::translate_mat(_center); } /** * Fills in the information in this record based on the information given in * the indicated datagram, whose opcode has already been read. Returns true * on success, false if the datagram is invalid. */ bool FltTransformRotateScale:: extract_record(FltRecordReader &reader) { if (!FltTransformRecord::extract_record(reader)) { return false; } nassertr(reader.get_opcode() == FO_rotate_and_scale, false); DatagramIterator &iterator = reader.get_iterator(); iterator.skip_bytes(4); // Undocumented additional padding. _center[0] = iterator.get_be_float64(); _center[1] = iterator.get_be_float64(); _center[2] = iterator.get_be_float64(); _reference_point[0] = iterator.get_be_float64(); _reference_point[1] = iterator.get_be_float64(); _reference_point[2] = iterator.get_be_float64(); _to_point[0] = iterator.get_be_float64(); _to_point[1] = iterator.get_be_float64(); _to_point[2] = iterator.get_be_float64(); _overall_scale = iterator.get_be_float32(); _axis_scale = iterator.get_be_float32(); _angle = iterator.get_be_float32(); iterator.skip_bytes(4); // Undocumented additional padding. recompute_matrix(); check_remaining_size(iterator); return true; } /** * Fills up the current record on the FltRecordWriter with data for this * record, but does not advance the writer. Returns true on success, false if * there is some error. */ bool FltTransformRotateScale:: build_record(FltRecordWriter &writer) const { if (!FltTransformRecord::build_record(writer)) { return false; } writer.set_opcode(FO_put); Datagram &datagram = writer.update_datagram(); datagram.pad_bytes(4); // Undocumented additional padding. datagram.add_be_float64(_center[0]); datagram.add_be_float64(_center[1]); datagram.add_be_float64(_center[2]); datagram.add_be_float64(_reference_point[0]); datagram.add_be_float64(_reference_point[1]); datagram.add_be_float64(_reference_point[2]); datagram.add_be_float64(_to_point[0]); datagram.add_be_float64(_to_point[1]); datagram.add_be_float64(_to_point[2]); datagram.add_be_float32(_overall_scale); datagram.add_be_float32(_axis_scale); datagram.add_be_float32(_angle); datagram.pad_bytes(4); // Undocumented additional padding. return true; }