indexing description: "[ A wrapper / adaptor for a drawable to make it rotateable and zoomable. The position and size of such objects is defined through the transformed drawable. Changing the position of an EM_TRANSFORMER is possible (`set_x_y') but changing any of the transformation parameters will recalculate `Current's position. EM_TRANSFORMER should not be used to excessively because it uses a buffer to draw the drawable before rotating it. Especially when you only want to zoom and/or scroll your drawable, better use an EM_ZOOMABLE_CONTAINER. ]" date: "$Date$" revision: "$Revision$" class EM_TRANSFORMER inherit EM_DRAWABLE DOUBLE_MATH EM_SHARED_SUBSYSTEMS export {NONE} all end EM_SHARED_BITMAP_FACTORY export {NONE} all end create make_with_drawable feature -- Initialization make_with_drawable (a_drawable: EM_DRAWABLE) is -- Initialize `Current' to transform `a_drawable' when drawing. do initialize_events drawable := a_drawable create rotation_center.make (drawable.width / 2, drawable.height / 2) zoom_factor := 1.0 rotation_angle := 0 if video_subsystem.video_surface /= Void then is_anti_aliasing_enabled := video_subsystem.video_surface.is_anti_aliasing_enabled else is_anti_aliasing_enabled := True end set_visible (True) ensure drawable_set: drawable = a_drawable end feature -- Status report drawable: EM_DRAWABLE -- Drawable that is transformed zoom_factor: DOUBLE -- Zoom factor by which to zoom `drawable' rotation_center: EM_VECTOR_2D -- Rotation center relative to position of `drawable' rotation_angle: DOUBLE -- Rotation angle by which to rotate `drawable' around `rotation_center' (in degree) width: INTEGER -- Width of `Current' height: INTEGER -- Height of `Current' is_anti_aliasing_enabled: BOOLEAN -- Is the transformation done with anti aliasing? feature -- Status setting set_drawable (a_drawable: EM_DRAWABLE) is -- Set `drawable' to `a_drawable'. require a_drawable_not_void: a_drawable /= Void do drawable := a_drawable update_bounding_box ensure drawable_set: drawable = a_drawable end set_zoom_factor (a_zoom_factor: DOUBLE) is -- Set `zoom_factor' to `a_zoom_factor'. require a_zoom_factor_positive: a_zoom_factor > 0 do zoom_factor := a_zoom_factor update_bounding_box ensure zoom_factor_set: zoom_factor = a_zoom_factor end set_rotation_center (a_position: EM_VECTOR_2D) is -- Set `rotation_center' to `a_position'. require a_position_not_void: a_position /= Void do rotation_center := a_position update_bounding_box ensure rotation_center_set: rotation_center = a_position end set_rotation_angle (an_angle: DOUBLE) is -- Set `rotation_angle' to `an_angle' in degrees. do rotation_angle := an_angle update_bounding_box ensure rotation_angle_set: rotation_angle = an_angle end set_anti_aliasing_enabled (a_bool: BOOLEAN) is -- Set `is_anti_aliasing_enabled' to `a_bool'. do is_anti_aliasing_enabled := a_bool ensure is_anti_aliasing_enabled_set: is_anti_aliasing_enabled = a_bool end update_bounding_box is -- Calculate `bounding_box' where `Current' draws the transformed `drawable'. local bbox: EM_ORTHOGONAL_RECTANGLE p1, p2, p3, p4: EM_VECTOR_2D angle_in_rad: DOUBLE x1, y1, x2, y2: DOUBLE do bbox := drawable.bounding_box bbox.zoom (zoom_factor) -- Calculate rotated position. angle_in_rad := rotation_angle * Pi / 180 p1 := bbox.upper_left.rotation (rotation_center, - angle_in_rad) p2 := bbox.upper_right.rotation (rotation_center, - angle_in_rad) p3 := bbox.lower_right.rotation (rotation_center, - angle_in_rad) p4 := bbox.lower_left.rotation (rotation_center, - angle_in_rad) -- Calculate and set bounding box. x1 := p1.x.min (p2.x).min (p3.x). min (p4.x) y1 := p1.y.min (p2.y).min (p3.y). min (p4.y) x2 := p1.x.max (p2.x).max (p3.x). max (p4.x) y2 := p1.y.max (p2.y).max (p3.y). max (p4.y) x := x1.floor y := y1.floor width := x2.ceiling - x height := y2.ceiling - y end draw (a_drawing_interface: EM_SURFACE) is -- Draw `Current' with `a_drawing_interface'. local zoomed_width: INTEGER zoomed_height: INTEGER transformed_drawable: EM_SURFACE -- buffer do if is_visible then -- Create a buffer with right width and height for zooming the drawable. zoomed_width := (drawable.width * zoom_factor).ceiling zoomed_height := (drawable.height * zoom_factor).ceiling Bitmap_factory.create_empty_surface (zoomed_width, zoomed_height) transformed_drawable := Bitmap_factory.last_surface transformed_drawable.set_anti_aliasing_enabled (is_anti_aliasing_enabled) -- Zoom the drawable (transform coordinates to draw it zoomed). transformed_drawable.transform_coordinates (drawable.bounding_box) drawable.draw (transformed_drawable) -- Rotate the zoomed buffer. if (rotation_angle.rounded \\ 360) /= 0 then transformed_drawable.rotate (rotation_angle) end -- Draw the transformed drawable at `Current's position. a_drawing_interface.blit_surface (transformed_drawable, x, y) end end end