indexing description: "[ A resizeable box that contains a graphical representation of a coordinate axis. Axis-boxes use the Viz-coordinate system, with the Y-axis pointing downwards, and the Z-axis pointing away from the viewer! Subclasses will need to implement update_blips and update_labels to add blips and labels to the axis. This class only provides the basics for subclasses like EM_VIZ_LINEAR_AXIS_BOX. ]" author: "" date: "$Date$" revision: "$Revision$" deferred class EM_VIZ_AXIS_BOX inherit EM_VIZ_BOX redefine update, vz_cache, vz_setup, vz_revert end EM_VIZ_RESIZEABLE feature -- Initialization make_axis (a_length: like axis_length; an_axis_index: INTEGER; invert_axis: BOOLEAN) is -- Make new axis of `a_length' and `invert_axis' if neccessary require valid_axis: valid_axis (an_axis_index) do make_box make_resizeable ([0.0, 0.0, 0.0]) create_labels create_blips set_label_rotation (0.0) set_label_distance (default_label_distance) set_label_alignment ([Align_center, Align_center]) set_axis_inverted (invert_axis) set_axis_index (an_axis_index) set_axis_length (a_length) put_head_arrow prune_tail_arrow end feature -- Access X_axis: INTEGER is 1 -- X-axis index Y_axis: INTEGER is 2 -- Y-axis index Z_axis: INTEGER is 3 -- Z-axis index label_rotation: DOUBLE -- Rotation in degrees of labels label_alignment: EM_ALIGNMENT_2D -- Alignment of labels default_label_distance: DOUBLE is 5.0 -- Default label distance label_distance: DOUBLE -- Distance of labels from axis has_head_arrow: BOOLEAN -- Draw head arrow (in positive direction) has_tail_arrow: BOOLEAN -- Draw tail arrow (in negative direction) axis_index: INTEGER -- Axis index (one of X_axis, Y_axis, Z_axis) axis_inverted: BOOLEAN -- Should axis be inverted? axis_length: DOUBLE -- Length of axis do Result := size [axis_index] end feature -- Status report valid_axis (an_axis: INTEGER): BOOLEAN is -- Is `an_axis' valid? do Result := X_axis <= an_axis and an_axis <= Z_axis end feature -- Element change set_axis_inverted (invert: like axis_inverted) is -- Set inversion flag for current axis do axis_inverted := invert expire ensure set: axis_inverted = invert expired: needs_update end put_head_arrow is -- Head arrow will be rendered do has_head_arrow := True expire ensure has: has_head_arrow expired: needs_update end prune_head_arrow is -- Head arrow will not be rendered do has_head_arrow := False expire ensure pruned: not has_head_arrow expired: needs_update end put_tail_arrow is -- Tail arrow will be rendered do has_tail_arrow := True expire ensure has: has_tail_arrow expired: needs_update end prune_tail_arrow is -- Tail arrow will not be rendered do has_tail_arrow := False expire ensure pruned: not has_tail_arrow expired: needs_update end set_label_distance (a_dist: like label_distance) is -- Set label distance from axis do label_distance := a_dist expire ensure set: label_distance = a_dist expired: needs_update end set_label_alignment (an_alignment: like label_alignment) is -- Set label alignment do label_alignment := an_alignment expire ensure set: label_alignment = an_alignment expired: needs_update end set_label_rotation (deg: like label_rotation) is -- Set label rotation do label_rotation := deg expire ensure set: label_rotation = deg expired: needs_update end set_axis_index (an_axis_index: like axis_index) is -- Set axis index to one of X_axis, Y_axis, or Z_axis require valid_axis: valid_axis (an_axis_index) do axis_index := an_axis_index expire ensure set: axis_index = an_axis_index expired: needs_update end set_axis_length (a_length: like axis_length) is -- Set length of axis local s: like size do s := size s [axis_index] := a_length set_size_internal (s) ensure set: axis_length = a_length end feature -- Update mechanism update is -- Update internal state do blips.wipe_out labels.wipe_out update_blips update_labels update_dimensions Precursor end feature {NONE} -- Rendering axis_vertex (fract: DOUBLE): EM_VECTOR3D is -- Axis vertex as fraction of axis do Result := axis_origin + axis_vector.scaled (fract) end render_axis_labels is -- Render axis labels local l: TUPLE [fract: DOUBLE; text: EM3D_STRING] s, e: like label_offset do from labels.start until labels.off loop l := labels.item_for_iteration e := axis_vertex (l.fract) s := e + label_offset render_link (s, e, False, False) l.text.render_rotated_and_aligned (s, label_rotation, label_alignment) labels.forth end end vz_setup is -- Setup local coordinate system do Precursor setup_local_coordinate_frame end vz_revert is -- Revert do revert_local_coordinate_frame Precursor end vz_render (viewing_direction: EM_VECTOR3D) is -- Render stuff do render_axis ( axis_vertex (0.0), axis_vertex (1.0), has_tail_arrow, has_head_arrow, blips ) render_axis_labels end vz_cache is -- Cache all labels do -- map cache labels from labels.start until labels.off loop labels.item_for_iteration.text.cache labels.forth end Precursor end feature {EM_VIZ_AXIS_BOX} -- Implementation label_offset: EM_VECTOR3D -- Offset of labels from vertex on axis as a vector axis_vector: EM_VECTOR3D -- Vector that points in direction of the axis axis_origin: EM_VECTOR3D -- Axis origin inside box update_blips is -- Update blips (using put_blip) deferred end update_labels is -- Update labels (using put_label) deferred end put_blip (fract: DOUBLE) is -- Insert blip at fraction of axis do blips.force_last (fract) end put_label (fract: DOUBLE; text: STRING) is -- Insert label at fraction of axis do create_label (text) labels.force_last ([fract, last_label]) end update_dimensions is -- Update bounding box to fit labels, but only in dimensions -- orthogonal to axis local c, s: DOUBLE lbb, obb: EM_INTERVAL_2D lbb_anchor, loff: EM_VECTOR2D do lbb := max_label_bbox lbb_anchor := lbb.align_value (lbb_anchor.zero, label_alignment) c := cosine (degrees_to_radians (label_rotation)) s := sine (degrees_to_radians (label_rotation)) obb.set ([-label_distance, -label_distance], [label_distance, label_distance]) loff := - obb.align_value (label_offset.zero, label_alignment) label_offset.set ( c * loff.x - s * loff.y, s * loff.x + c * loff.y, 0.0 ) lbb.rotate ( degrees_to_radians (label_rotation), lbb_anchor ) lbb.translate (label_offset - lbb_anchor) lbb.accommodate_value (label_offset.zero) inspect axis_index when X_axis then set_height_internal (lbb.height) axis_origin := [0.0, -lbb.min.y, depth] when Y_axis then set_width_internal (lbb.width) axis_origin := [-lbb.min.x, 0.0, depth] when Z_axis then set_width_internal (lbb.width) set_height_internal (lbb.height) axis_origin := [-lbb.min.x, -lbb.min.y, 0.0] else check false end end axis_vector := axis_vector.zero axis_vector [axis_index] := axis_length if axis_inverted then axis_origin := axis_origin + axis_vector axis_vector := - axis_vector end end feature {NONE} -- Implementation max_label_bbox: EM_INTERVAL_2D is -- Find biggest label bounding-box do Result.set ([0.0,0.0], [0.0,0.0]) from labels.start until labels.off loop Result.accommodate_interval (labels.item_for_iteration.text.bounding_box) labels.forth end end blips: DS_LINKED_LIST [DOUBLE] -- Blips labels: DS_LINKED_LIST [TUPLE [fract: DOUBLE; text: EM3D_STRING]] -- Labels create_blips is -- Create blips storage do create blips.make ensure blips_exist: blips /= Void end create_labels is -- Create labels storage do create labels.make ensure labels_exist: labels /= Void end invariant labels_exist: labels /= Void blips_exist: blips /= Void end