indexing description: "[ A coordinate frame that can be used to map coordinates from a local coordinate system to a global one. This mapping is represented by a matrix internally. ]" author: "" date: "$Date$" revision: "$Revision$" class EM_VIZ_COORDINATE_FRAME inherit EM_VIZ_MATH export {NONE} all end create make, make_unit, make_box_mapping, make_from_matrix, make_from_quaternion convert make_from_matrix ({EM_MATRIX44}), make_from_quaternion ({EM_QUATERNION}), to_matrix: {EM_MATRIX44} feature -- Initialization make_unit is -- Make unity frame do matrix.set_unit end make (xa, ya, za, org: EM_VECTOR3D) is -- Create new coordinate frame, with `xa' as X-axis, `ya' as Y-axis, -- `za' as Z-axis, and `org' as origin do matrix.set_unit set_x_axis (xa) set_y_axis (ya) set_z_axis (za) set_origin (org) ensure set: x_axis = xa and y_axis = ya and z_axis = za and origin = org end make_box_mapping (target, source: EM_INTERVAL_3D) -- Create mapping from points inside of `source' to points inside of `targets' -- Boundary points will be mapped to boundary points again require non_deformed_source: source.width > 0.0 and source.height > 0.0 and source.depth > 0.0 do make_box_mapping_from_corners (target, source.min, source.max) end make_box_mapping_from_corners (target: EM_INTERVAL_3D; pstart, pend: EM_VECTOR3D) is -- Create mapping from points in AABB from `pstart' to `pend' to `target' require non_deformed_source: pstart.x - pend.x /= 0.0 and pstart.y - pend.y /= 0.0 and pstart.z - pend.z /= 0.0 local s, org: EM_VECTOR3D do s := target.size.ew_divided (pend - pstart) org := target.min - pstart.ew_multiplied (s) make_unit set_origin (org) set_x_axis ([s.x, 0.0, 0.0]) set_y_axis ([0.0, s.y, 0.0]) set_z_axis ([0.0, 0.0, s.z]) ensure -- Finite precision demands this be commented out: -- pstart_mapped_to_min: target.min = map (pstart) -- pend_mapped_to_max: target.max = map (pend) end make_box_mapping_with_inverted_axes (target, source: EM_INTERVAL_3D; invert_x, invert_y, invert_z: BOOLEAN) is -- Create mapping from points inside of `source' to poins inside of `targets' -- If `invert_x', the x-coordinates will be inverted -- Ditto for `invert_y' and `invert_z' local xs, xe, ys, ye, zs, ze: DOUBLE do if invert_x then xs := source.x.max; xe := source.x.min else xs := source.x.min; xe := source.x.max end if invert_y then ys := source.y.max; ye := source.y.min else ys := source.y.min; ye := source.y.max end if invert_z then zs := source.z.max; ze := source.z.min else zs := source.z.min; ze := source.z.max end make_box_mapping_from_corners (target, [xs,ys,zs], [xe,ye,ze]) end make_from_matrix (m: EM_MATRIX44) -- Create coordinate frame from matrix `m' describing an -- affine transformation of points in 3d. require matrix_is_affine: -- m.det /= 0.0 and -- Not really neccessary. -- m.row (4) = [0.0, 0.0, 0.0, 1.0] do matrix := m matrix.set_row ([0.0,0.0,0.0,1.0], 4) end make_from_quaternion (q: EM_QUATERNION) -- Create coordinate frame from quaternion do matrix.make_from_quaternion (q) end make_concatenation (outer, inner: EM_VIZ_COORDINATE_FRAME) -- Create coordinate frame representing concatenation of -- outer and inner require avoid_destructive_update: Current /= outer do matrix := outer.matrix * inner.matrix ensure -- definition: -- x_axis = outer.map (inner.x_axis) and -- y_axis = outer.map (inner.y_axis) and -- z_axis = outer.map (inner.z_axis) and -- origin = outer.map (inner.origin) end feature -- Basic operations map (point: EM_VECTOR3D): EM_VECTOR3D is -- Map `point' from current coordinate frame to global coordinates local v4h: EM_VECTOR4D do v4h := [point.x, point.y, point.z, 1.0] v4h := matrix.mult (point.to_vector4d) Result := v4h.to_vector3d end inversed: like Current is -- Inversed `current' do create Result.make_from_matrix (matrix.inversed) end feature -- Access x_axis: EM_VECTOR3D is -- X-axis in global coordinates do Result := (matrix.column (1)).to_vector3d end y_axis: EM_VECTOR3D is -- Y-axis in global coordinates do Result := (matrix.column (2)).to_vector3d end z_axis: EM_VECTOR3D is -- Z-axis in global coordinates do Result := (matrix.column (3)).to_vector3d end origin: EM_VECTOR3D is -- The point in global coordinates at which current -- coordinate system is anchored do Result := (matrix.column (4)).to_vector3d end feature -- Element change set_x_axis (v: EM_VECTOR3D) is -- Set x-axis to `v' do matrix.set_column ([v.x, v.y, v.z, 0.0], 1) ensure set: x_axis = v end set_y_axis (v: EM_VECTOR3D) is -- Set y-axis to `v' do matrix.set_column ([v.x, v.y, v.z, 0.0], 2) ensure set: y_axis = v end set_z_axis (v: EM_VECTOR3D) is -- Set z-axis to `v' do matrix.set_column ([v.x, v.y, v.z, 0.0], 3) ensure set: z_axis = v end set_origin (p: EM_VECTOR3D) is -- Set origin to `p' do matrix.set_column ([p.x, p.y, p.z, 1.0], 4) ensure set: origin = p end feature -- Conversion to_matrix: EM_MATRIX44 is -- Convert to matrix do Result := matrix end feature -- Transformation concatenate (inner: EM_VIZ_COORDINATE_FRAME) is -- Concatenate current frame with an `inner' frame do matrix := matrix * inner end scaled (xs, ys, zs: DOUBLE) is -- Scale local coordinates by `xs', `ys', and `zs' do scale ([xs, ys, zs]) end scale (factors: EM_VECTOR3D) is -- Scale local coordinates by some `factors' -- Comparable to emgl_scaled do set_x_axis (x_axis.scaled (factors.x)) set_y_axis (y_axis.scaled (factors.y)) set_z_axis (z_axis.scaled (factors.z)) end translated (tx, ty, tz: DOUBLE) is -- Translate local coordinates by `tx', `ty', and `tz' do translate ([tx, ty, tz]) end translate (offset: EM_VECTOR3D) is -- Translate local coordinates by some `offset' -- Comparable to emgl_translated do set_origin (origin + map_point (offset)) end rotated (degrees: DOUBLE; axis_x, axis_y, axis_z: DOUBLE) is -- See `rotate' do rotate (degrees, [axis_x, axis_y, axis_z]) end rotate (degrees: DOUBLE; axis: EM_VECTOR3D) is -- Rotate local coordinates by some `degrees' around `axis' -- Comparable to emgl_rotated local quat: EM_QUATERNION do quat.set_from_rotation (axis, degrees_to_radians (degrees)) set_x_axis (quat.rotate_vector3 (x_axis)) set_y_axis (quat.rotate_vector3 (y_axis)) set_z_axis (quat.rotate_vector3 (z_axis)) end map_point (local_point: EM_VECTOR3D): EM_VECTOR3D is -- Map `local_point' from this frame to global do Result := map (local_point) end map_points (local_points: DS_LINEAR [EM_VECTOR3D]; mapped_points: DS_LIST [EM_VECTOR3D]) is -- Map `local_points' from this frame to global, store results in `mapped_points' require points_exist: local_points /= Void and mapped_points /= Void do from local_points.start mapped_points.wipe_out until local_points.off loop mapped_points.force_last (matrix.mult (local_points.item_for_iteration)) local_points.forth end ensure all_mapped: local_points.count = mapped_points.count end feature {EM_VIZ_COORDINATE_FRAME} -- Implementation matrix: EM_MATRIX44 -- Matrix describing transformation from current coordinate frame to -- global coordinate system -- The matrix is composed like this: -- -- | xa.x xa.y xa.z ap.x | -- | ya.x ya.y ya.z ap.y | -- matrix = | za.x za.y za.z ap.z | -- | 0 0 0 1 | -- -- The transformation itself: -- -- p_global := origin + p.x * x_axis + p.y * y_axis + p * z_axis end